How to deploy AWS CDK stacks to multiple accounts? - amazon-web-services

AWS CDK stacks target an account or region based on an evironment, details here. Here is an example of an app that deploys one stack into multiple target accounts:
const envEU = { account: '2383838383', region: 'eu-west-1' };
const envUSA = { account: '8373873873', region: 'us-west-2' };
new MyFirstStack(app, 'first-stack-eu', { env: envEU });
new MyFirstStack(app, 'first-stack-us', { env: envUSA });
My question is how to deploy these 2 stacks - is it possible to deploy them as a single operation? If so, what credentials are used and what roles are required on the 2 accounts?
Ideally, I'd like to be able to do a single command to deploy all stacks across all accounts:
cdk deploy ...
Or is the deployment only possible via 2 steps?
cdk deploy first-stack-eu --profile=profile_for_account_2383838383
cdk deploy first-stack-us --profile=profile_for_account_8373873873

I ended up using the cdk-assume-role-credential-plugin to perform the task. The description of that plugin states:
This plugin allows the CDK CLI to automatically obtain AWS credentials
from a stack's target AWS account. This means that you can run a
single command (i.e. cdk synth) with a set of AWS credentials, and the
CLI will determine the target AWS account for each stack and
automatically obtain temporary credentials for the target AWS account
by assuming a role in the account.
I wrote up a detailed tutorial on how to use this plugin to perform AWS cross-account deployments using CDK here: https://johntipper.org/aws-cdk-cross-account-deployments-with-cdk-pipelines-and-cdk-assume-role-credential-plugin/

In cloudformation you can use Stack Sets for multi-account and multi-region deployments.
However, this is not yet supported in CDK according to the GitHub issue:
Support for CloudFormation StackSets #66

As of v2 of CDK this is available by default:
Now by default when you bootstrap an AWS account it will create a set of IAM roles for you, which the CDK will assume when performing actions in that account.

If you have multiple stacks in your app you have to pass every stack into the cdk deploy command e.g. cdk deploy WmStackRouteCertStack004BE231 WmStackUploadStackF8C20A98
I don't know of a way to deploy all stacks in an app, I don't like this behavior and it's the reason I try to avoid creating multiple stacks

Related

Can awscli be used in AWS Codebuild buildspec running on a custom image?

If a Codebuild project runs on a custom image that has awscli preinstalled, but not configured for that AWS account, would it be still possible to run aws * in that project's buildspec without updating its AWS credentials there first?
In other words, are these credentials made available by Codebuild (e.g. via providing this information in automatically picked up environment variables) , or if I am using a custom image, it is up to me to take care of that explicitly, and aws * is only expected to work in buildspec out of the box without additional efforts on Codebuild managed images?
(I mean configuration/credentials for the account and role the Codebuild project in question operates in)
When you attach an IAM service role with your AWS Codebuild project, you don't need to configure AWS cli. IAM service role is part of environment configuration and this role will be assumed whenever you try to access resources in AWS. This goes same for your custom image for AWS Codebuild as well.

AWS CDK Running `cdk synth` for Another Account

When use AWS CDK to provision resources in an VPC, it requires me to specify AWS account and region through env environment variables.
I have CLI access to my dev account, but no access to prod account.
I would like to use cdk synth to generate cloudformation template for production account. To do that, I specifies the account ID in .env file.
But cdk synth command returns me following error.
[Error at /whitespace-app-fargate/whitespace-app-fargate/FargateStack] Could not assume role in target account using current credentials (which are for account xxxxxxxx) User: arn:aws:iam::xxxxxxxxx:user/myqinjie is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::yyyyyyyyy:role/cdk-hnb659fds-lookup-role-yyyyyyyy-ap-southeast-1 . Please make sure that this role exists in the account. If it doesn't exist, (re)-bootstrap the environment with the right '--trust', using the latest version of the CDK CLI.
Is there a ways to run cdk synth to generate cloudformation template without validation?
It is not possible to run cdk synth against an account that you do not have access to.
You need use a role or user that has sufficient permissions to execute cdk synth against production account.
May I ask what is your usecase?
If you want to validate which resources will be created, you can run against your own account but use production stage and production region.
The only thing different when effectively deploying to production will be the account.

How to use cdk cross-account access with OIDC and EKS

Followed this link: Enabling cross-account access to Amazon EKS cluster resources
I can make a pod in an Amazon EKS cluster hosted in ci account interact and manage the AWS resources in a target account.
This is the aws config file:
[profile ci-env]
role_arn = arn:aws-cn:iam::CICD_ACCOUNT:role/eksctl-jenkins-cicd-demo-addon-iamserviceacc-Role1-1AQZO394370HE
web_identity_token_file = /var/run/secrets/eks.amazonaws.com/serviceaccount/token
region = cn-north-1
[profile target-env]
role_arn = arn:aws-cn:iam::TARGET_ACCOUNT:role/target-account-iam-role
source_profile = ci-env
role_session_name = xactarget
region = cn-north-1
When I run aws s3 ls --profile target-env, it worked and listed the s3 buckets in my target account.
Then, I want to deploy a cdk app on ci account which can create s3 bucket on target account.
But When I run cdk deploy --profile target-env, it appeared:
Need to perform AWS calls for account TARGET_ACCOUNT, but no credentials have been configured.
I am very confused and don't know how to solve it.
I am a beginner of aws service, thanks advance for helping me!
You need to bootstrap all of your (target) accounts to trust the CICD account.
Otherwise, you would have to create and manage the cross-account access by yourself.
IAM Roles + Policies (in all accounts)
S3 Bucket for artifacts + bucket policies (in CICD account)
Key Management Service -> Customer Managed Key + Policies to allow the target accounts
You can spot here an example architecture, which is applying that:
If it's possible for you, you might switch to the CDK Pipelines.
In this guide, also the bootstrapping (incl. trusting) is being applied and every step/resource mentioned from above is being created and properly configured.
It has a few drawbacks as of now, but it's in developer preview and has a quite decent usability and makes your life a lot easier already.

AWS CDK: how to deploy resources to different accounts?

Is it possible to deploy resources to two different AWS accounts using CDK?
As a simple example, imagine 2 resources that are linked (2 different IAM roles, perhaps), that need to be deployed to accounts accountA and accountB. They are linked, so their lifecycles should be tied together (i.e. they are created and destroyed at the same time and I shouldn't have to run two deployment actions). I'd like to be able to specify at deployment time where the resources go, not at synthesis time.
This requirement is easily achieved using Terraform (by means of two different provisioner definitions). How do I achieve this using CDK? Can this be achieved within a single stack, or is the CDK model that of one stack per target account? What does a simple example look like?
Yes, this is possible. you need to pass environment config object to stack props.
From the docs:
Each Stack instance in your AWS CDK app is explicitly or implicitly
associated with an environment (env). An environment is the target AWS
account and AWS Region into which the stack is intended to be
deployed.
Usage:
const envEU = { account: '2383838383', region: 'eu-west-1' };
const envUSA = { account: '8373873873', region: 'us-west-2' };
new MyFirstStack(app, 'first-stack-us', { env: envUSA, encryption: false });
new MyFirstStack(app, 'first-stack-eu', { env: envEU, encryption: true });
More info here.
In case you want to deploy 2 different resources within the same stack to 2 different accounts, this is not supported yet.
You would need to create different stack for each resource and pass the environment object accordingly.

aws codepipline update lambda function source using s3 object

I am using terraform to create all the infra(CodePipeline, lambda, buckets) on AWS
currently, I've created a pipeline that builds the source zip file and puts it on s3 bucket but the lambda still keeps using the older source. So, I update the URL manually in the AWS console and it works.
Now I want to automate the flow but available solutions are:
AWS SAM + CFT
Codebuild Stage to update the source using AWS CLI
Create a lambda that updates the source
Code Deploy + AWS SAM + CFT
I am not willing to use CFT at all since all of our code is in terraform and CFT requires me to create new lambdas instead of using old ones.
is there any other simpler way to update the lambda source through Codepipeline
The preferred way to deploy a Lambda via CodePipeline is using a CloudFormation Deploy action [1]. Since you are not looking to use CloudFormation, next option could be to run your terraform plan/apply commands from within a CodeBuild job that is part of the pipeline. You will need to provide the CodeBuild role required permission for resource creation (or export the credentials in Environment variabels for TF to use via this [2] method) and install the TF binary within install phase of buildspec.
Ref:
[1] Building a Continuous Delivery Pipeline for a Lambda Application with AWS CodePipeline - https://docs.aws.amazon.com/lambda/latest/dg/build-pipeline.html
[2] How to retrieve Secret Manager data in buildspec.yaml