Skip to content

Commit 55cc9d3

Browse files
committed
added example of oidc
1 parent 3bf792a commit 55cc9d3

File tree

1 file changed

+195
-0
lines changed

1 file changed

+195
-0
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Deploy to an S3 bucket from GitHub
2+
3+
This guide gives a quick, secure way to build a simple static website in GitHub, and deploy it to an S3 bucket in AWS.
4+
5+
For that to work, GitHub needs permissions on the S3 bucket. The standard approach is to use a specific AWS access_key and secret_token. But, even if you use GitHub Secrets, you're still then exposing an access token to GitHub.
6+
7+
OIDC is an alternative approach whereby GitHub gets granted temporary access to a specific role in AWS. This further lets you limit that role using IAM: to specific buckets and actions.
8+
9+
The process flow for OIDC is:
10+
1. GitHub Action triggers from your git commit
11+
2. GitHub Action assumes a role in AWS
12+
3. (behind the scenes, GitHub and AWS use OIDC: exchanging JWT tokens to grant GitHub temporary access to a specific role in AWS)
13+
4. GitHub Action uses that role to copy files into an S3 bucket
14+
15+
One-time setup to get this working:
16+
1. Define GitHub as an Identity Provider in your AWS account
17+
2. Define what GitHub is allowed to do (IAM policy)
18+
3. Define the GitHub role (IAM role)
19+
4. Define the GitHub Action
20+
21+
NB: You should script as much of this as possible, where it is safe to do so.
22+
23+
## Define GitHub as an identity provider in your AWS account
24+
25+
This is done by adding GitHub as an IdP Provider in AWS.
26+
27+
Follow steps to create IdP provider:
28+
https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services
29+
30+
31+
## Define what GitHub is allowed to do
32+
33+
This is done by creating an AWS Role Profile, stating exactly which buckets GitHub will be allowed to deploy into.
34+
35+
Create new Policy ("GitHubS3DeployPolicy")
36+
37+
```json
38+
{
39+
"Version": "2012-10-17",
40+
"Statement": [
41+
{
42+
"Effect": "Allow",
43+
"Action": [
44+
"s3:*",
45+
"s3-object-lambda:*"
46+
],
47+
"Resource": [
48+
"arn:aws:s3:::your-s3-bucket/*",
49+
"arn:aws:s3:::your-s3-bucket"
50+
]
51+
}
52+
]
53+
}
54+
```
55+
56+
## Define the GitHub role
57+
58+
This is the role that GitHub will assume. It:
59+
- Links to the policy created early
60+
- Links to the github OIDC created early
61+
- Explicitly states which GitHub repo, and branches are permitted
62+
63+
This page includes many options, including using Cognito, etc.
64+
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_oidc.html
65+
66+
Below is a full, simple example that doesn't use Cognito.
67+
68+
Create a new Role ("GitHubS3DeployRole")
69+
Trust policy:
70+
71+
```json
72+
{
73+
"Version": "2012-10-17",
74+
"Statement": [
75+
{
76+
"Effect": "Allow",
77+
"Principal": {
78+
"Federated": "arn:aws:iam::<YOUR_AWS_ACCOUNT_NUMBER>:oidc-provider/token.actions.githubusercontent.com"
79+
},
80+
"Action": "sts:AssumeRoleWithWebIdentity",
81+
"Condition": {
82+
"StringEquals": {
83+
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
84+
"token.actions.githubusercontent.com:sub": "repo:<YOUR_GITHUB_ORG>/<YOUR_GITHUB_REPO>:ref:refs/heads/main"
85+
}
86+
}
87+
}
88+
]
89+
}
90+
```
91+
Attach the policy created earlier ("GitHubS3DeployPolicy")
92+
93+
94+
## Define the GitHub Action
95+
96+
Define ASSUME_ROLE_ARN ("GitHubS3DeployRole" from earlier) and AWS_S3_BUCKET_NAME in GitHub Repo Secrets.
97+
Example below just syncs the "view-stack" folder into the s3 bucket.
98+
99+
```yaml
100+
name: deploy-radar
101+
102+
on:
103+
push:
104+
branches:
105+
- main
106+
107+
jobs:
108+
build:
109+
permissions:
110+
id-token: write
111+
contents: read
112+
runs-on: ubuntu-latest
113+
timeout-minutes: 10
114+
steps:
115+
- name: Checkout
116+
uses: actions/checkout@v3
117+
118+
- name: Authenticate with AWS over OIDC
119+
uses: aws-actions/configure-aws-credentials@v2
120+
with:
121+
role-to-assume: ${{ secrets.ASSUME_ROLE_ARN }}
122+
role-session-name: mysessionname
123+
aws-region: eu-west-2
124+
- name: Copy files to the s3 website content bucket
125+
run:
126+
aws s3 sync myfolder s3://${{ secrets.AWS_S3_BUCKET_NAME }}/myfolder
127+
aws s3 sync myotherfolder s3://${{ secrets.AWS_S3_BUCKET_NAME }}/myotherfolder
128+
```
129+
130+
All done!
131+
132+
## Testing
133+
134+
Some basic test cases below. Add your own too!
135+
You should look to automate these where possibly.
136+
I've included my specific tests, and results - some helpful notes in there.
137+
138+
Ensure success
139+
- GitHub: edit "view-stack/index.html"
140+
- Commit to "main" branch
141+
- Expecting:
142+
- Build should clearly pass
143+
- Build should be quick (<10 min)
144+
- Bucket contents updated
145+
- Bucket timestamp updated
146+
- No previous version stored in bucket (we're not versionsing)
147+
- RESULT: PASS. Took 21 seconds, 18 of those in copying the files. Expect that to grow as files get bigger, but remain under 10 mins. Add a timeout to the GitHub action to enforce that time limit.
148+
149+
Ensure GitHub Action: only triggers on "main" branch
150+
- GitHub: make a new branch and commit
151+
- Expecting:
152+
- Action does NOT trigger
153+
- S3 bucket is not updated
154+
- Because:
155+
- Should only trigger on "main" branch (ci.yml: on:push:branches: - main)
156+
- RESULT: PASS
157+
158+
Ensure Role Policy: fails when has wrong S3 bucket name
159+
- AWS: edit "GitHubS3DeployPolicy". Change S3 bucket name to something random.
160+
- Kick off another github workflow on "main"
161+
- Expecting:
162+
- Build should clearly fail
163+
- Nothing redeployed to S3 bucket
164+
- Because:
165+
- Role Policy says explicitly which bucket name this role is allowed to deploy into
166+
- Auth should still work, but aws s3 command should fail with access denied.
167+
- RESULT: PASS
168+
- Run aws s3 sync view-stack s3://***/view-stack
169+
10fatal error: An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
170+
11Error: Process completed with exit code 1.
171+
172+
Ensure Role: fails when has wrong GitHub Repo name
173+
- AWS: edit "GitHubS3DeployRole" Trust Policy. Change GitHub Repo in "token.actions.githubusercontent.com:sub" to something random: "repo:NHSDigitalWRONG/tech-radar:ref:refs/heads/main"
174+
- Kick off another github workflow on "main"
175+
- Expecting:
176+
- Build should clearly fail
177+
- Nothing redeployed to S3 bucket
178+
- Because:
179+
- Role's trust policy says explicitly which GitHub repo is allowed to use this role
180+
- RESULT: PASS, with notes:
181+
- Authentication failed: Error: Not authorized to perform sts:AssumeRoleWithWebIdentity
182+
- But took 2min, seemed to be timing out / retrying
183+
184+
Ensure Role fails when has wrong GitHub Branch name:
185+
- AWS: edit "GitHubS3DeployRole" Trust Policy. Change GitHub branch in "token.actions.githubusercontent.com:sub" to something random: "repo:NHSDigital/tech-radar:ref:refs/heads/mainWRONG"
186+
- Kick off another github workflow on "main"
187+
- Expecting:
188+
- Workflow SHOULD still trigger (GitHub action still has "main" as the branch to trigger on)
189+
- Build should clearly fail
190+
- Nothing redeployed to S3 bucket
191+
- Because:
192+
- Role's trust policy says explicitly which branches of the GitHub repo are allowed to use this role
193+
- RESULT: PASS, with notes:
194+
- Authentication failed: Error: Not authorized to perform sts:AssumeRoleWithWebIdentity
195+
- But took 2min, seemed to be timing out / retrying

0 commit comments

Comments
 (0)