この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
RedashのCICD用にIAMロールを作っていました。後々のメンテナンスを面倒にしないことが一番の課題です。
RedashのDeploy用IAMロール及びIAMユーザ作成にYAMLのCloudFormationテンプレートを使う方をよく見ますが、正直YAMLでは書きたくないなーというのが本音でした。インデントで関係が見やすいとしても依存等は追いかけ難い。個人的には「cdkでもいいんじゃない?」と思いますが、やってる人が少なくてゼロから検証するのも確かに手間です。
ただ、誰もやってなさそうなので「やってみた」系ネタとしては有用かなと思い、cdkでやってみました。
今回の前提
IAMロール作成用スタックを環境作成用スタックに含めた上で、IAMロール作成用スタックのみを指定実行します。
既にIAMユーザは存在しており、Arnで指定します。ポイントはロール作成に用いるclass。ロールを引き受けつつセッションタグを受け渡すため、以下のActionを設定する必要があります。
- sts:AssumeRole
- sts:TagSession
複数のActionをAssumeRoleActionに割り当てる手段
classにRoleを用いた場合、assumedBy
に渡すIPrincipal
は要素のassumeRoleAction
がstringのみ受け付けており、複数Actionは配列扱いとなるため適用できません。IPrincipal
は@aws-cdk/aws-iamのClassで実装されており、assumeRoleAction
を引数として受け付けるClass全てで該当しています。ではどうすべきか。
Actionに2つ割り当てた例として以下の記事があります。
What I ended up with, is to use a low-level construct CfnRole.
とあるように、CfnRoleを使い、assumeRolePolicyDocument
に渡す形にて実装例を以下に挙げます。
CfnRoleを用いた実装
ManagedPolicyは枠に上限があるため、アスタリスクでActionが指定されていたり、Action数が少ないものについてはPolicyDocumentとして纏めて追加しています。
import { CfnOutput, Construct, Stack, StackProps } from '@aws-cdk/core';
import { ManagedPolicy, CfnRole, Effect, PolicyDocument, PolicyStatement } from'@aws-cdk/aws-iam';
export class RedashDeployRoleStack extends Stack {
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
const deployRole = new CfnRole(this, 'RedashDeployRoleStack', {
roleName: `redash-deploy`,
assumeRolePolicyDocument: {
'Statement': [{
'Effect': Effect.ALLOW,
'Action': ['sts:AssumeRole', 'sts:TagSession'],
'Principal': {
'AWS': `arn:aws:iam::${this.account}:user/redash-user`,
}
}]
},
managedPolicyArns: [
ManagedPolicy.fromAwsManagedPolicyName('AmazonECS_FullAccess').managedPolicyArn,
ManagedPolicy.fromAwsManagedPolicyName('AmazonRDSFullAccess').managedPolicyArn,
ManagedPolicy.fromAwsManagedPolicyName('AmazonElastiCacheFullAccess').managedPolicyArn,
ManagedPolicy.fromAwsManagedPolicyName('AmazonRoute53FullAccess').managedPolicyArn
],
maxSessionDuration: 60 * 60 * 12,
// AmazonVPCFullAccess
// AWSCloudFormationFullAccess
// IAMFullAccess
// AmazonSSMReadOnlyAccess
policies: [{
policyName: `RedashDeployPolicy`,
policyDocument: new PolicyDocument({
statements: [
new PolicyStatement({
actions: [
"cloudformation:*",
"iam:*",
"ec2:*",
"ssm:Describe*",
"ssm:Get*",
"ssm:List*"
],
resources: ["*"]
}),
]
}).toJSON()
}]
});
// output
new CfnOutput(this, 'RedashDeployRole', {
value: deployRole.attrArn,
description: 'RoleArn for Deploy'
});
}
}
Deploy用にcdk.tsへ追記します。
import { App } from '@aws-cdk/core';
import { RedashDeployRoleStack } from '../lib/deploy-role';
const env = {account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION}
const app = new App({
context: {
version: process.env.VERSION
}
});
const roleStack = new RedashDeployRoleStack(app, `redash-deploy-role`, {env});
手軽に実行できるよう、バッチ化します。
#!/bin/sh
npm run build
npm run cdk -- deploy --require-approval never --context redash-deploy-role
実行後、ログに出力されるArnをGitHub上でSecretsに指定し、aws-actions/configure-aws-credentials
のrole-to-assume
に渡します。
Outputs:
redash-deploy-role.RedashDeployRole = arn:aws:iam::000000000000:role/redash-deploy
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
role-to-assume: ${{ secrets.AWS_ROLE_FOR_REDASH }}
role-duration-seconds: 3600
あとがき
ActionsのWorkflowを動作させるために必要なため、実行する場所は手元の作業環境に限定されます。ActionsのWorkflow上ではnochangesで終わるはずですが、万が一意図しない変更が発生していた場合は不要な修正が含まれていないか差分を確認しましょう。