From d613e2ff519109acd6f159127c9b1181e67e4622 Mon Sep 17 00:00:00 2001 From: Harri Salokorpi Date: Wed, 11 Dec 2024 11:10:14 +0200 Subject: [PATCH] WIP: push frontend to s3 --- .github/actions/push_s3/action.yml | 32 +++++++++++ .github/workflows/build.yml | 8 +++ aoe-infra/infra/lib/front-end-bucket-stack.ts | 57 +++++++++++-------- .../lib/front-end-content-deployment-stack.ts | 28 ++++----- aoe-infra/infra/lib/utility-stack.ts | 44 +++++++------- 5 files changed, 110 insertions(+), 59 deletions(-) create mode 100644 .github/actions/push_s3/action.yml diff --git a/.github/actions/push_s3/action.yml b/.github/actions/push_s3/action.yml new file mode 100644 index 00000000..44e6bb72 --- /dev/null +++ b/.github/actions/push_s3/action.yml @@ -0,0 +1,32 @@ +name: Push S3 +description: Upload built static frontend data to s3 +inputs: + source-dir: + description: Source directory to upload + required: true + aws-region: + description: AWS region + required: true + aws-s3-bucket: + description: AWS S3 bucket + required: true + aws-access-key-id: + description: AWS access key id + required: true + aws-secret-access-key: + description: AWS access key secret + required: true + +runs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: jakejarvis/s3-sync-action@master + with: + args: --follow-symlinks --delete --exclude '.git*/*' + env: + SOURCE_DIR: ${{ input.source-dir }} + AWS_REGION: ${{ input.aws-region }} + AWS_S3_BUCKET: ${{ input.aws-s3-bucket }} + AWS_ACCESS_KEY_ID: ${{ input.aws-access-key-id }} + AWS_SECRET_ACCESS_KEY: ${{ input.aws-secret-access-key }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3970ab99..048414de 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,4 +76,12 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} aws-arn: ${{ secrets.AWS_AOE_UTILITY_ROLE_ARN }} image-tag: ga-${{ github.run_number }} + - name: Push S3 + uses: ./.github/actions/push_s3 + with: + source-dir: ./aoe-frontend/dist/ + aws-region: eu-west-1 + aws-s3-bucket: aoe-static-content-dev/aoe-frontend/ga-${{ github.run_number }} + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/aoe-infra/infra/lib/front-end-bucket-stack.ts b/aoe-infra/infra/lib/front-end-bucket-stack.ts index 2a1f4b20..2102ad3c 100644 --- a/aoe-infra/infra/lib/front-end-bucket-stack.ts +++ b/aoe-infra/infra/lib/front-end-bucket-stack.ts @@ -1,35 +1,46 @@ -import { Stack, StackProps } from 'aws-cdk-lib'; -import { Construct } from 'constructs'; +import * as cdk from 'aws-cdk-lib/core' import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; import * as origins from 'aws-cdk-lib/aws-cloudfront-origins'; +import { Stack, StackProps } from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import { BucketAccessControl, ObjectOwnership } from 'aws-cdk-lib/aws-s3' +import { RemovalPolicy } from 'aws-cdk-lib/core' interface FrontendBucketStackProps extends StackProps { - // domain: string - environment: string, - cloudFrontDistribution: cloudfront.Distribution, - } - + environment: string, + cloudFrontDistribution: cloudfront.Distribution, +} + export class FrontendBucketStack extends Stack { readonly bucket: s3.Bucket; constructor(scope: Construct, id: string, props: FrontendBucketStackProps) { - super(scope, id, props); + super(scope, id, props); + + // FrontEnd S3 bucket - OAI does not support KMS - encryption + this.bucket = new s3.Bucket(this, 'FrontEndBucket', { + bucketName: `aoe-static-content-${props.environment}`, + enforceSSL: true, + accessControl: BucketAccessControl.PRIVATE, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + versioned: true, // Required for taking backups + objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED, // Required for restoring backups + lifecycleRules: [ + { + id: 'ExpireOldVersions', + noncurrentVersionExpiration: cdk.Duration.days(30), // Retain old versions for 30 days + } + ], + removalPolicy: RemovalPolicy.RETAIN + }); -// FrontEnd S3 bucket - OAI does not support KMS - encryption - this.bucket = new s3.Bucket(this, 'FrontEndBucket', { - bucketName: `aoe-static-content-${props.environment}`, - enforceSSL: true, - // encryption: s3.BucketEncryption.KMS, - // encryptionKey: props.s3KmsKey, - }); + // CloudFront OAI, Origin & behaviour + const s3oai = new cloudfront.OriginAccessIdentity(this, 'OAI'); + const s3origin = new origins.S3Origin(this.bucket, { originAccessIdentity: s3oai }); -// CloudFront OAI, Origin & behaviour - const s3oai = new cloudfront.OriginAccessIdentity(this, 'OAI'); - const s3origin = new origins.S3Origin(this.bucket, { originAccessIdentity: s3oai }); - - props.cloudFrontDistribution.addBehavior('/static/*', s3origin, { - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS - }); + props.cloudFrontDistribution.addBehavior('/static/*', s3origin, { + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS + }); } -} \ No newline at end of file +} diff --git a/aoe-infra/infra/lib/front-end-content-deployment-stack.ts b/aoe-infra/infra/lib/front-end-content-deployment-stack.ts index 0ef90ea2..c25e6db6 100644 --- a/aoe-infra/infra/lib/front-end-content-deployment-stack.ts +++ b/aoe-infra/infra/lib/front-end-content-deployment-stack.ts @@ -8,21 +8,21 @@ import * as path from 'path'; interface FrontendStaticContentDeploymentStackProps extends StackProps { // domain: string - environment: string, - cloudFrontDistribution: cloudfront.Distribution, - bucket: s3.Bucket, - } - + environment: string, + cloudFrontDistribution: cloudfront.Distribution, + bucket: s3.Bucket, +} + export class FrontendStaticContentDeploymentStack extends Stack { constructor(scope: Construct, id: string, props: FrontendStaticContentDeploymentStackProps) { - super(scope, id, props); + super(scope, id, props); - new s3deploy.BucketDeployment(this, 'XXXXXX', { - sources: [s3deploy.Source.asset(path.join(__dirname, '../frontend/dist'))], - destinationBucket: props.bucket, - destinationKeyPrefix: 'static', - distribution: props.cloudFrontDistribution, - distributionPaths: ['/static/*'], - }); + new s3deploy.BucketDeployment(this, 'XXXXXX', { + sources: [s3deploy.Source.asset(path.join(__dirname, '../aoe-web/frontend/dist'))], + destinationBucket: props.bucket, + destinationKeyPrefix: 'static', + distribution: props.cloudFrontDistribution, + distributionPaths: ['/static/*'], + }); } -} \ No newline at end of file +} diff --git a/aoe-infra/infra/lib/utility-stack.ts b/aoe-infra/infra/lib/utility-stack.ts index e1db7b6f..9f379482 100644 --- a/aoe-infra/infra/lib/utility-stack.ts +++ b/aoe-infra/infra/lib/utility-stack.ts @@ -5,31 +5,31 @@ import { Construct } from 'constructs'; export class UtilityStack extends cdk.Stack { public readonly githubActionsDeploymentRole: iam.Role; constructor(scope: Construct, id: string, props?: cdk.StackProps) { - super(scope, id, props); + super(scope, id, props); -// Github Actions OIDC role - const githubOidcProvider = new iam.OpenIdConnectProvider(this, `OvaraUtilityGithubOidcProvider`, { - url: 'https://token.actions.githubusercontent.com', - thumbprints: [ - '6938fd4d98bab03faadb97b34396831e3780aea1', - '1c58a3a8518e8759bf075b76b750d4f2df264fcd' - ], - clientIds: ['sts.amazonaws.com'], - }); + // Github Actions OIDC role + const githubOidcProvider = new iam.OpenIdConnectProvider(this, `OvaraUtilityGithubOidcProvider`, { + url: 'https://token.actions.githubusercontent.com', + thumbprints: [ + '6938fd4d98bab03faadb97b34396831e3780aea1', + '1c58a3a8518e8759bf075b76b750d4f2df264fcd' + ], + clientIds: ['sts.amazonaws.com'], + }); - this.githubActionsDeploymentRole = new iam.Role(this, `AoeUtilityGithubActionsUser`, { - assumedBy: new iam.WebIdentityPrincipal( - githubOidcProvider.openIdConnectProviderArn, - { - StringLike: { - 'token.actions.githubusercontent.com:sub': 'repo:Opetushallitus/aoe:*', - 'token.actions.githubusercontent.com:aud': 'sts.amazonaws.com', - }, - }, - ), - roleName: 'aoe-utility-github-actions-deployment-role', - }); + this.githubActionsDeploymentRole = new iam.Role(this, `AoeUtilityGithubActionsUser`, { + assumedBy: new iam.WebIdentityPrincipal( + githubOidcProvider.openIdConnectProviderArn, + { + StringLike: { + 'token.actions.githubusercontent.com:sub': 'repo:Opetushallitus/aoe:*', + 'token.actions.githubusercontent.com:aud': 'sts.amazonaws.com', + }, + }, + ), + roleName: 'aoe-utility-github-actions-deployment-role', + }); } }