Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/argo-pr-env/serviceaccount.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ kind: ServiceAccount
metadata:
name: workflow-runner-sa
namespace: ${NAMESPACE}
annotations:
eks.amazonaws.com/role-arn: ${AWS_IRSA_ROLE_ARN}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/argo-pr-env-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
packages: write
env:
AWS_CI_ROLE: ${{ secrets.AWS_CI_ROLE }}
AWS_IRSA_ROLE_ARN: ${{ secrets.AWS_IRSA_ROLE_ARN }}
CLUSTER_NAME: Workflows
NAMESPACE: pr-${{ github.event.number }}
steps:
Expand Down Expand Up @@ -42,7 +43,7 @@ jobs:
- name: Create ServiceAccount
run: |
# shellcheck disable=SC2016
envsubst '${NAMESPACE}' < .github/argo-pr-env/serviceaccount.yaml | kubectl apply -f -
envsubst '${NAMESPACE},${AWS_IRSA_ROLE_ARN}' < .github/argo-pr-env/serviceaccount.yaml | kubectl apply -f -
- name: Deploy Semaphore config
run: |
# shellcheck disable=SC2016
Expand Down
50 changes: 37 additions & 13 deletions infra/eks/cluster.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { KubectlV30Layer } from '@aws-cdk/lambda-layer-kubectl-v30';
import { Aws, CfnOutput, Duration, RemovalPolicy, SecretValue, Size, Stack, StackProps } from 'aws-cdk-lib';
import { Aws, CfnJson, CfnOutput, Duration, RemovalPolicy, SecretValue, Size, Stack, StackProps } from 'aws-cdk-lib';
import * as chatbot from 'aws-cdk-lib/aws-chatbot';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import * as actions from 'aws-cdk-lib/aws-cloudwatch-actions';
Expand Down Expand Up @@ -278,25 +278,49 @@ export class LinzEksCluster extends Stack {
kind: 'Namespace',
metadata: { name: 'argo' },
});

// SA for the `argo` namespace (production) - IRSA is also created by `addServiceAccount()`
const argoRunnerSa = this.cluster.addServiceAccount('ArgoRunnerServiceAccount', {
name: 'workflow-runner-sa',
namespace: 'argo',
});
argoRunnerSa.node.addDependency(argoNs);
new CfnOutput(this, CfnOutputKeys.ArgoRunnerServiceAccountName, { value: argoRunnerSa.serviceAccountName });

// give read/write on the temporary (scratch) bucket
this.tempBucket.grantReadWrite(argoRunnerSa.role);
// give permission to the sa to assume a role
argoRunnerSa.role.addToPrincipalPolicy(new PolicyStatement({ actions: ['sts:AssumeRole'], resources: ['*'] }));
// IRSA for the `pr-*` namespaces (development)
const oidcProvider = this.cluster.openIdConnectProvider;
const condition = new CfnJson(this, 'OIDCCondition', {
value: {
[`${oidcProvider.openIdConnectProviderIssuer}:aud`]: 'sts.amazonaws.com',
[`${oidcProvider.openIdConnectProviderIssuer}:sub`]: `system:serviceaccount:pr-*:workflow-runner-sa`,
},
});

const prIRSA = new iam.Role(this, 'PRWildcardRole', {
assumedBy: new iam.FederatedPrincipal(
oidcProvider.openIdConnectProviderArn,
{
StringLike: condition, // we want to allow all `pr-*` (pr-1234, pr-2345, etc.) namespaces
},
'sts:AssumeRoleWithWebIdentity',
),
});

// Set the permissions for the IRSA
for (const role of [argoRunnerSa.role, prIRSA]) {
// give read/write on the temporary (scratch) bucket
this.tempBucket.grantReadWrite(role);
// give permission to the sa to assume a role
role.addToPrincipalPolicy(new PolicyStatement({ actions: ['sts:AssumeRole'], resources: ['*'] }));

/* Gives read access on ODR public buckets.
* While those are public buckets, we still need to give permission to Argo
* as the `--no-sign-request` is not handled in the code.
*/
Bucket.fromBucketName(this, 'OdrNzCoastal', 'nz-coastal').grantRead(argoRunnerSa.role);
Bucket.fromBucketName(this, 'OdrNzElevation', 'nz-elevation').grantRead(argoRunnerSa.role);
Bucket.fromBucketName(this, 'OdrNzImagery', 'nz-imagery').grantRead(argoRunnerSa.role);
Bucket.fromBucketName(this, 'OdrNzTopography', 'nz-topography').grantRead(argoRunnerSa.role);
/* Gives read access on ODR public buckets.
* While those are public buckets, we still need to give permission to Argo
* as the `--no-sign-request` is not handled in the code.
*/
Bucket.fromBucketName(this, `OdrNzCoastal-${role.roleName}`, 'nz-coastal').grantRead(role);
Bucket.fromBucketName(this, `OdrNzElevation-${role.roleName}`, 'nz-elevation').grantRead(role);
Bucket.fromBucketName(this, `OdrNzImagery-${role.roleName}`, 'nz-imagery').grantRead(role);
Bucket.fromBucketName(this, `OdrNzTopography-${role.roleName}`, 'nz-topography').grantRead(role);
}
}
}
Loading