Oh look another post about SST. I'm currently in the middle of moving a big Next.js repo from GitLab to GitHub and off DigitalOcean and onto AWS. Naturally I've used SST to do this. It did take me a little while to get this setup properly though.
sst.config.ts
The first step is defining your profile correctly. If you don't set it to undefined
when running a GitHub Action it ain't gonna work.
Here's an example config:
/// <reference path="./.sst/platform/config.d.ts" />
import { readdirSync } from 'fs';
export default $config({
app(input) {
return {
name: 'app',
removal: input?.stage === 'production' ? 'retain' : 'remove',
home: 'aws',
providers: {
aws: {
region: 'eu-west-2',
profile: process.env.GITHUB_ACTIONS
? undefined
: input?.stage === 'production'
? 'acme-production'
: 'acme-dev',
},
},
};
},
async run() {
const outputs = {};
for (const value of readdirSync('./infra/')) {
const result = await import('./infra/' + value);
if (result.outputs) Object.assign(outputs, result.outputs);
}
return outputs;
},
});
Allowing GitHub Access To AWS
To allow GitHub access to AWS, you can Configure OpenID Connect in Amazon Web Services. We can actually do this in our infra code, rather than through our AWS account by using some of the Pulumi constructs built into SST.
Define the following in your sst.config.ts
(or in an /infra
directory), where GITHUB_ORG
and GITHUB_REPO
are your values:
export default $config (
{...},
async run() {
const github = new aws.iam.OpenIdConnectProvider("GithubProvider", {
url: "https://token.actions.githubusercontent.com",
clientIdLists: ["sts.amazonaws.com"],
});
const githubRole = new aws.iam.Role("GithubRole", {
name: [$app.name, $app.stage, "github"].join("-"),
assumeRolePolicy: {
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Principal: {
Federated: github.arn,
},
Action: "sts:AssumeRoleWithWebIdentity",
Condition: {
StringLike: github.url.apply((url) => ({
[`${url}:sub`]: "repo:${GITHUB_ORG}/${GITHUB_REPO}:*",
})),
},
},
],
},
});
new aws.iam.RolePolicyAttachment("GithubRolePolicy", {
policyArn: "arn:aws:iam::aws:policy/AdministratorAccess",
role: githubRole.name,
});
})
Then deploy this.
The GitHub Action
Once GitHub has access to your AWS resources, you can add a workflow file to your repo (again, make sure you add your app name, expected stage and AWS account number):
name: deploy-app
on:
push-branches:
- [main]
release:
types: [published]
concurrency:
group: ${{ github.ref }}
permissions:
id-token: write
contents: read
jobs:
install_dependencies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "20"
- name: Cache dependencies
uses: actions/cache@v3
with:
path: |
**/node_modules
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --frozen-lockfile
deploy:
needs: [install_dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: "20"
- uses: actions/cache@v2
with:
path: |
.sst
key: ${{ runner.os }}-sst
- run: "curl -fsSL https://ion.sst.dev/install | bash"
- name: Configure AWS credentials (Production)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${AWS_ACCOUNT_NUMBER}:role/${APP_NAME}-${APP_STAGE}-github
aws-region: eu-west-2
#
- name: Deploy
run: |
sst install
sst deploy --stage production --verbose
Yeah I'm still using yarn
sorry.
Resources
- The terminal.shop repo has a great workflow example: Github: terminaldotshop/terminal/infra
- SST Docs
- Configure OpenID Connect in Amazon Web Services