本日のお題
前回、「GitHubからAWSに認証を行う(OIDCを使用)」というのをAWS CDKで実装しました。
今回はその逆で、「AWSからGitHubに認証を行う」というのをAWS CDKで実装します。(AWS CodePipelineでCI/CDを構成する際に必要になります)
なお、よく使われる&ブログ記事でも多いのは「個人アクセストークン(GitHub Personal Access Token、以下PAT)を使う方法」なのですが、この記事では「接続(CodeStar接続)」で行う方法を扱います。
上記を実施する際に必要な手順
CodeStar接続を使うメリット
個人ユーザーに依存しない
PATは個人ユーザーに紐づくため、例えば部署移動や退職などでそのユーザーが抜けてしまった場合、使用できなくなります。
そのため、アプリでPAT使用していると、思わぬ事故(=突然接続できなくなった)の原因になりますし、またそれを管理しておく必要があります。
CodeStar接続は該当のGitHubリポジトリに紐づくので、そういったことは起こりません。(間違ってGitHubアプリを削除してしまった...などが起こる可能性はありますが...)
セキュリティ的な問題
PATは有効期限があり、期限切れ前にアプリ側のPATも更新しなければならず、管理が手間になりますし、無期限だとセキュリティ的に問題です。
またPATが漏洩したらそれだけで該当GitHubに接続できてしまうので、セキュリティ的にも問題になります。
CodeStar接続には有効期限はありませんし、仮にARNが漏洩してもそれだけで該当GitHubに接続できてしまうということはありません。(操作者に該当CodeStar接続を使用する権限がなければ接続できない)
GitHub Enterpriseでも使える
AWS CDKのソースアクション(aws-cdk-lib.aws_codepipeline_actions
)には、GitHub Enterprise(以下GHE)専用のアクションがないので、GHEにPATで接続できません。
そのためGHEに接続する場合、PAT以外での接続が必須になります。
ちなみにGitHubの場合、codepipeline_actions.GitHubSourceAction
から下記のようにPATを使って接続できます。(AWS CDK公式より)
const sourceAction = new codepipeline_actions.GitHubSourceAction({ actionName: 'GitHub_Source', owner: '<GitHubアカウントまたはorganization名>', repo: '<リポジトリ名>', oauthToken: `<PATの値>`, output: sourceOutput, // アーティファクトの出力先 branch: 'develop', // default: 'master' });
なおAWS CDKでは、CodeStar接続以外に下記ソースプロバイダのアクションが用意されています。
- GitHub
- CodeCommit
- ECR
- S3
CodeStar接続の作成&GitHub Appの作成&インストール
以下の手順で、CodeStar接続を作成します。
CodePipeline左ツリーの [設定] - [接続] から、「接続の作成」をクリックする
プロバイダー(GitHub, GHEなど)、及び接続名を選択・入力する
「AWS Connector for <プロバイダー名> by ...」という画面が表示されるので、「Authorize AWS Connector...」ボタンをクリックする
「GitHubに接続する」という画面が表示されるので「新しいアプリをインストールする」をクリックする
- すでに別でGitHubアプリを作成済なら既存のアプリを選択します。
この後GitHubの認証画面が表示されるので、ログイン情報を入力する。
- なおOwners権限をもったアカウントでログインしないとGitHubアプリの作成ができません。
「GitHubに接続する」画面で「接続」をクリックする
- GitHubアプリ名に何か値が表示されているはずです
「<接続名>」画面で「ステータス」が「接続可能」になっていればOKです
CodeStar接続の作成が完了したら、そのARNをコピペしておきます。(AWS CDKで使います)
ちなみに、CodeStar接続自体はAWS CDKでも作成できますが「作成できるのは接続名のみで、GitHubアプリは手作業で作成しないといけない」という理由から、今回は手作業で作成しました。
AWS CDKの実装
では、AWS CDKの実装になります。
なおボリュームの関係で、CodeStar接続に関する部分(=ソースアクション)のみ記載します。
AWS CodePipelineとCDK Pipeline、及びその違いの説明は省略します。(とりあえず「そういうものがあるんだ」くらいの認識で問題ありません。)
AWS CodePipelineの場合
// CodePipelineで使うIAM Role const pipelineRole = new iam.Role(this, 'codePipelineRole', { assumedBy: new iam.ServicePrincipal('codepipeline.amazonaws.com'), roleName: 'codePipelineRole', managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('ReadOnlyAccess')], }); // サービスプリンシパルにCodeBuildを追加(接続だけなら不要かも) pipelineRole.assumeRolePolicy.addStatements( new iam.PolicyStatement({ // Restrict to listing and describing tables principals: [new iam.ServicePrincipal('codebuild.amazonaws.com')], actions: ['sts:AssumeRole'], effect: iam.Effect.ALLOW, }), ); // 上記Roleに追加するIAMポリシー const pipelineInlinePolicy = new iam.Policy(this, 'pipelineInlinePolicy', { // CodePipelineにcodestar-connections:UseConnectionを許可するポリシー。 // これがないとCodeStar接続ができないので注意!!! policyName: 'pipelineInlinePolicy', statements: [ new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['codestar-connections:UseConnection'], resources: [<作成したCodeStar接続のArn>], }), // あと、CodeBuildで必要なアクションの許可だったり、 // Artifactバケットへのアクセス許可だったりを定義 new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['codebuild:StartBuild', 'codebuild:BatchGetBuilds'], resources: [`arn:aws:codebuild:${this.region}:${this.account}:project/*`], }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['s3:*'], resources: [`<ArtifactバケットのARN>`, `<ArtifactバケットのARN>/*`], }), }); pipelineRole.attachInlinePolicy(pipelineInlinePolicy); // ソースアクションの設定 const sourceArtifact = new codepipeline.Artifact(); const sourceAction = new actions.CodeStarConnectionsSourceAction({ actionName: 'CodeStarConnectionsSourceAction', // ここで作成したCodeStar接続のARNを設定するのが重要 connectionArn: `<作成したCodeStar接続のARN>`, output: sourceArtifact, owner: '<GitHubのアカウントororganization名(=repoの「/」の左側)>', repo: '<対象のリポジトリ名>', // デフォルトはmaster(mainじゃない) branch: '<対象のブランチ名>', // 先に作成しておいたIAM Roleを設定する。 // これがないと接続に失敗するので注意 role: pipelineRole, // この2つはデフォルト値(同じなら設定不要) // runOrder: 1, // triggerOnPush: true, });
CDK Pipelineの場合
// IAM Roleや割り当てポリシーはAWS CodePipelineと同じなので省略 // AWS CodePipeline同様、IAM Roleでcodestar-connections:UseConnectionを // CodePipeline(CodeBuildも?)に許可しないと接続が失敗するので注意 const steps = new CodeBuildStep('CodeBuildStep', { commands: ['npm run build', 'npx cdk synth'], actionRole: pipelineRole, // inputにCodePipelineSource.connectionメソッドで接続情報を指定する。 // ここが重要!!! input: CodePipelineSource.connection('<対象のリポジトリ名>', '<対象のブランチ名>', { connectionArn: `<作成したCodeStar接続のARN>`, triggerOnPush: true, }), installCommands: ['npm install'], role: pipelineRole, }); new CodePipeline(this, 'Pipeline', { pipelineName: ’CDKPipelineSample’, synth: steps, role: pipelineRole, });
接続できない場合
GitHubと接続ができない場合、主に下記の原因が考えられるので、確認してみてください。(もちろん他にもあります)
CDKの定義ミス
そもそもCDKの定義が間違っていないかを確認します。(意外とARNが間違っていたり、typoが原因だったりします)
GHE側の接続制限(GHE)
GHEの場合、セキュリティ上の理由で、GitHub側で「ホワイトリストに登録したIPアドレスしか接続を許可していない」というケースがあります。
この場合、下記の対応が必要になります。
- AWS CodePipelineをVPCに入れる
- そのVPCから外部にアクセスするリソース(NATなど)にパブリックIP(Elastic IPなど)を割り当てる
- 上記IPアドレスをホワイトリストに追加する
細かい説明は省略しますが、この場合は [設定] - [接続] の「ホスト」タブでVPCを使用するホストを作成することで接続可能になります。
まとめ
以上、AWS CodePipelineでGitHubと認証する方法でした。
PATは簡単な判明、今回記載したような事項もあったり、GitHub Enterpriseだといろいろ制限があったりするので、その場合は今回のCodeStar接続を使うことになります。
ちょっとややこしいですが、いろいろ便利な面もあるので、ぜひ有効に活用してください。
それでは、今回はこの辺で。