Skip to content

Commit

Permalink
VA-411-1-2: Create load balancer for VA application
Browse files Browse the repository at this point in the history
Create security groups in separate stack as they caused cyclic dependency issues.
  • Loading branch information
anttu committed May 21, 2024
1 parent 5e31032 commit cfc0d04
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 74 deletions.
55 changes: 42 additions & 13 deletions cdk/bin/cdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { DbStack } from '../lib/db-stack'
import { BastionStack } from '../lib/bastion-stack'
import { EcsStack } from '../lib/ecs-stack'
import { EncryptionStack } from '../lib/encryption-stack'
import { SecurityGroupStack } from '../lib/security-group-stack'
import { PersistentResourcesStack } from '../lib/persistent-resources-stack'

const HAKIJA_DOMAIN = 'valtionavustukset.oph.fi'
const HAKIJA_DOMAIN_SV = 'statsunderstod.oph.fi'
Expand All @@ -21,23 +23,36 @@ const app = new cdk.App()
{
const dev = new Environment(app, 'dev')
const vpcStack = new VpcStack(dev, 'vpc')
const securityGroupStack = new SecurityGroupStack(dev, 'security-group', vpcStack.vpc)
const encryptionStack = new EncryptionStack(dev, 'encryption')
const dbStack = new DbStack(dev, 'db', vpcStack.vpc, encryptionStack.dbEncryptionKey)
const ecsStack = new EcsStack(dev, 'ecs', vpcStack.vpc)
const vaService = new VaServiceStack(
const persistentResources = new PersistentResourcesStack(
dev,
'persistent-resources',
encryptionStack.logGroupEncryptionKey
)
const dbStack = new DbStack(
dev,
'application',
'db',
vpcStack.vpc,
ecsStack.ecsCluster,
dbStack.permitDBAccessSecurityGroup,
encryptionStack.logGroupEncryptionKey,
dbStack.clusterWriterEndpointHostname
securityGroupStack.securityGroups.dbSecurityGroup,
encryptionStack.dbEncryptionKey
)
const ecsStack = new EcsStack(dev, 'ecs', vpcStack.vpc)
const vaService = new VaServiceStack(dev, 'application', {
vpc: vpcStack.vpc,
cluster: ecsStack.ecsCluster,
applicationLogGroup: persistentResources.applicationLogGroup,
db: {
hostname: dbStack.clusterWriterEndpointHostname,
passwordSecret: persistentResources.databasePasswordSecret,
},
securityGroups: securityGroupStack.securityGroups,
})
const bastionStack = new BastionStack(
dev,
'bastion',
ecsStack.ecsCluster,
dbStack.permitDBAccessSecurityGroup
securityGroupStack.securityGroups.dbAccessSecurityGroup
)
const dns = new DnsStack(dev, 'dns', {
hakijaDomain: `dev.${HAKIJA_DOMAIN}`,
Expand All @@ -58,14 +73,21 @@ const app = new cdk.App()
{
const qa = new Environment(app, 'qa')
const vpcStack = new VpcStack(qa, 'vpc')
const securityGroupStack = new SecurityGroupStack(qa, 'security-group', vpcStack.vpc)
const encryptionStack = new EncryptionStack(qa, 'encryption')
const dbStack = new DbStack(qa, 'db', vpcStack.vpc, encryptionStack.dbEncryptionKey)
const dbStack = new DbStack(
qa,
'db',
vpcStack.vpc,
securityGroupStack.securityGroups.dbSecurityGroup,
encryptionStack.dbEncryptionKey
)
const ecsStack = new EcsStack(qa, 'ecs', vpcStack.vpc)
const bastionStack = new BastionStack(
qa,
'bastion',
ecsStack.ecsCluster,
dbStack.permitDBAccessSecurityGroup
securityGroupStack.securityGroups.dbAccessSecurityGroup
)
const dns = new DnsStack(qa, 'dns', {
hakijaDomain: `testi.${HAKIJA_DOMAIN}`,
Expand All @@ -87,14 +109,21 @@ const app = new cdk.App()
{
const prod = new Environment(app, 'prod')
const vpcStack = new VpcStack(prod, 'vpc')
const securityGroupStack = new SecurityGroupStack(prod, 'security-group', vpcStack.vpc)
const encryptionStack = new EncryptionStack(prod, 'encryption')
const dbStack = new DbStack(prod, 'db', vpcStack.vpc, encryptionStack.dbEncryptionKey)
const dbStack = new DbStack(
prod,
'db',
vpcStack.vpc,
securityGroupStack.securityGroups.dbSecurityGroup,
encryptionStack.dbEncryptionKey
)
const ecsStack = new EcsStack(prod, 'ecs', vpcStack.vpc)
const bastionStack = new BastionStack(
prod,
'bastion',
ecsStack.ecsCluster,
dbStack.permitDBAccessSecurityGroup
securityGroupStack.securityGroups.dbAccessSecurityGroup
)
new OphDnsStack(prod, 'oph-dns')
const dns = new DnsStack(prod, 'dns', {
Expand Down
16 changes: 3 additions & 13 deletions cdk/lib/db-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as cdk from 'aws-cdk-lib'
import { Environment } from './va-env-stage'
import { ParameterGroup } from 'aws-cdk-lib/aws-rds'
import { aws_kms, Duration } from 'aws-cdk-lib'
import { SecurityGroup } from 'aws-cdk-lib/aws-ec2'

export const DB_NAME = 'va'
export const DB_USER = 'va_cluster_admin'
Expand All @@ -14,6 +15,7 @@ export class DbStack extends cdk.Stack {
scope: Environment,
id: string,
vpc: cdk.aws_ec2.IVpc,
dbSecurityGroup: SecurityGroup,
storageEncryptionKey: aws_kms.Key,
props?: cdk.StackProps
) {
Expand All @@ -38,18 +40,6 @@ export class DbStack extends cdk.Stack {
securityGroupName: 'access-va-db-security-group',
})

const dbSecurityGroup = new cdk.aws_ec2.SecurityGroup(this, 'DBSecurityGroup', {
description: 'Security group for VA Postgres',
vpc,
allowAllOutbound: true,
securityGroupName: 'va-db-security-group',
})
dbSecurityGroup.addIngressRule(
accessVaDBSecurityGroup,
cdk.aws_ec2.Port.tcp(5432),
'Allow access from VA DB security group'
)

const auroraV2Cluster = new cdk.aws_rds.DatabaseCluster(this, 'AuroraV2Cluster', {
defaultDatabaseName: DB_NAME,
engine: cdk.aws_rds.DatabaseClusterEngine.AURORA_POSTGRESQL,
Expand All @@ -59,7 +49,7 @@ export class DbStack extends cdk.Stack {
vpcSubnets: { subnetType: cdk.aws_ec2.SubnetType.PRIVATE_ISOLATED },
serverlessV2MinCapacity: 0.5,
serverlessV2MaxCapacity: 4,
securityGroups: [dbSecurityGroup],
securityGroups: [dbSecurityGroup, accessVaDBSecurityGroup],
writer: cdk.aws_rds.ClusterInstance.serverlessV2('writer', {
enablePerformanceInsights: true,
}),
Expand Down
39 changes: 39 additions & 0 deletions cdk/lib/persistent-resources-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as cdk from 'aws-cdk-lib'
import { Environment } from './va-env-stage'
import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs'
import { aws_kms, RemovalPolicy } from 'aws-cdk-lib'
import { Secret } from 'aws-cdk-lib/aws-secretsmanager'

export class PersistentResourcesStack extends cdk.Stack {
databasePasswordSecret: Secret
applicationLogGroup: LogGroup

constructor(
scope: Environment,
id: string,
storageEncryptionKey: aws_kms.Key,
props?: cdk.StackProps
) {
super(scope, id, props)

// This password has been manually set using psql-va-[env].sh and CREATE USER 'va_application'
this.databasePasswordSecret = new Secret(this, 'va-db-user-password', {
secretName: '/db/password',
description: 'Valtionavustukset application DB password (username va_application)',
generateSecretString: {
passwordLength: 64,
requireEachIncludedType: true,
includeSpace: false,
excludePunctuation: true,
},
removalPolicy: RemovalPolicy.RETAIN,
})

this.applicationLogGroup = new LogGroup(this, 'va-log-group', {
logGroupName: '/fargate/valtionavustukset-application',
encryptionKey: storageEncryptionKey,
retention: RetentionDays.ONE_YEAR,
removalPolicy: RemovalPolicy.RETAIN,
})
}
}
75 changes: 75 additions & 0 deletions cdk/lib/security-group-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as cdk from 'aws-cdk-lib'
import { Environment } from './va-env-stage'
import { Peer, Port, SecurityGroup, IVpc } from 'aws-cdk-lib/aws-ec2'
import { CONTAINER_PORT } from './va-service-stack'

export interface VaSecurityGroups {
vaServiceSecurityGroup: SecurityGroup
dbSecurityGroup: SecurityGroup
albSecurityGroup: SecurityGroup
dbAccessSecurityGroup: SecurityGroup
}

export class SecurityGroupStack extends cdk.Stack {
securityGroups: VaSecurityGroups = {} as VaSecurityGroups

constructor(scope: Environment, id: string, vpc: IVpc, props?: cdk.StackProps) {
super(scope, id, props)

/* ---------- DB ---------- */
this.securityGroups.dbAccessSecurityGroup = new cdk.aws_ec2.SecurityGroup(
this,
'AccessVADBSecurityGroup',
{
vpc,
securityGroupName: 'allow-db-access',
description: 'Security group for accessing VA Postgres',
allowAllOutbound: true,
}
)

this.securityGroups.dbSecurityGroup = new cdk.aws_ec2.SecurityGroup(this, 'DBSecurityGroup', {
vpc,
securityGroupName: 'va-database',
description: 'Security group for VA Postgres',
allowAllOutbound: true,
})

this.securityGroups.dbSecurityGroup.addIngressRule(
this.securityGroups.dbAccessSecurityGroup,
cdk.aws_ec2.Port.tcp(5432),
'Allow access from VA DB security group'
)

/* ---------- VA Service ---------- */
this.securityGroups.vaServiceSecurityGroup = new SecurityGroup(this, 'va-app-sg', {
vpc: vpc,
securityGroupName: 'valtionavustukset-application',
description: 'Valtionavustukset application security group',
allowAllOutbound: true,
})

this.securityGroups.albSecurityGroup = new SecurityGroup(this, 'alb-sg', {
vpc,
securityGroupName: 'application-load-balancer',
description: 'Allow HTTP from public Internet',
allowAllOutbound: true,
})

this.securityGroups.albSecurityGroup.addIngressRule(
Peer.ipv4('62.165.154.10/32'),
Port.tcp(80),
'Allow access from Reaktor office'
)
this.securityGroups.albSecurityGroup.addEgressRule(
this.securityGroups.vaServiceSecurityGroup,
Port.tcp(CONTAINER_PORT),
'Allow egress to VA service'
)
this.securityGroups.vaServiceSecurityGroup.addIngressRule(
this.securityGroups.albSecurityGroup,
Port.tcp(CONTAINER_PORT),
'Allow access from ALB'
)
}
}

0 comments on commit cfc0d04

Please sign in to comment.