CDK Pipelines 2026年版|マルチアカウント対応CI/CD構築ガイド

AWS CDK Pipelinesを使ったエンタープライズグレードのCI/CD構築。セキュリティ強化、マルチアカウント対応、最新v2機能を完全解説。

CDK Pipelines 2026年版|マルチアカウント対応のCI/CD構築完全ガイド

はじめに

2026年のAWS CDKエコシステムは、Pipelines v2の全機能統合とマルチアカウント管理の自動化が進みました。本記事では、最新版のCDK Pipelinesを使用したエンタープライズグレードのCI/CD構築方法を、実装コード例を交えて解説します。

CDK Pipelinesは、Infrastructure as Codeの変更をGitリポジトリから自動検出し、クロスアカウント・クロスリージョンへのデプロイを完全に自動化する強力なツールです。2026年時点では、AWS CloudFormation CDK v2.130.0以降で提供されている最新の機能セットを活用できます。

2026年CDK Pipelinesの進化ポイント

2026年のCDK Pipelinesは、以下の重要なアップデートが施されています:

セキュリティ強化

  • IAM権限の最小化:Auto-discovery機能により、必要な権限のみが自動付与される
  • リポジトリ接続の改善:AWS CodeStarConnections v2によるGitHub Enterprise対応
  • シークレット管理:AWS Secrets Manager統合による認証情報の安全な管理

パフォーマンス向上

  • キャッシング機構:CloudFormation stackの差分検出が60%高速化
  • 並列実行:複数StackGroupの並列デプロイが標準対応
  • Cost Optimization:クロスアカウント構築時のAPI呼び出し削減

運用効率化

  • Wave概念の拡張:動的なWave定義でシーケンシャル・並列の柔軟な制御
  • カスタムアクション:Lambda/EventBridgeによるカスタムデプロイロジック
  • 監視・アラート:CloudWatch Synthetics統合でパイプライン状態の可視化

CDK Pipelines アーキテクチャの基本

graph LR
    subgraph "Source Stage"
        GH[GitHub Repository]
        CON[CodeStar Connection]
    end
    
    subgraph "Pipeline Stage"
        SELF[Self-Mutation]
        BUILD[Build Stage]
    end
    
    subgraph "Deploy Stages"
        DEV[Dev Account<br/>us-east-1]
        STAGING[Staging Account<br/>us-east-1]
        PROD_EAST[Prod Account<br/>us-east-1]
        PROD_WEST[Prod Account<br/>us-west-2]
    end
    
    subgraph "Verification"
        SMOKE[Smoke Tests]
        INTEG[Integration Tests]
        MON[Monitoring]
    end
    
    GH -->|Webhook| CON
    CON -->|Source| SELF
    SELF -->|Update| BUILD
    BUILD -->|Artifact| DEV
    DEV -->|Validation| SMOKE
    SMOKE -->|Pass| STAGING
    STAGING -->|Pass| PROD_EAST
    PROD_EAST -->|Replication| PROD_WEST
    PROD_EAST -->|Monitoring| MON
    STAGING -->|Integration| INTEG

実装例:マルチアカウントCI/CDパイプライン

ステップ1:パイプリーンスタック定義

import * as cdk from 'aws-cdk-lib';
import * as pipelines from 'aws-cdk-lib/pipelines';
import * as github from 'aws-cdk-lib/aws-codebuild';
import * as codeconnections from 'aws-cdk-lib/aws-codeconnections';

interface PipelineStackProps extends cdk.StackProps {
  gitHubRepo: string;
  gitHubBranch: string;
  connectionArn: string;
}

export class CdkPipelineStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props: PipelineStackProps) {
    super(scope, id, props);

    // 2026年版:CodeStar Connections v2を使用
    const sourceOutput = new pipelines.CodePipelineSource.gitHub(
      props.gitHubRepo,
      props.gitHubBranch,
      {
        actionName: 'GitHub_Source',
        // CodeStar Connectionsの接続ARNを指定
        trigger: pipelines.GitHubTrigger.WEBHOOK,
        // キャッシング有効化
        codestarConnectionArn: props.connectionArn,
      }
    );

    // パイプラインの定義
    const pipeline = new pipelines.CodePipeline(this, 'CDKPipeline', {
      pipelineName: 'cdk-pipelines-2026',
      synth: new pipelines.ShellStep('Synth', {
        input: sourceOutput,
        installCommand: 'npm install -g aws-cdk',
        commands: [
          'npm ci',
          'npm run build',
          'npx cdk synth',
        ],
        primaryOutputDirectory: 'cdk.out',
        // 2026年版:キャッシング設定
        cache: pipelines.FileCache.npm({
          location: '.npm',
        }),
      }),
      // Cross-account deployment用の設定
      crossAccountKeys: true,
      // セルフミューテーション有効化
      selfMutation: true,
      // Docker資格情報キャッシュ
      dockerEnabledForSynth: true,
      // 詳細ログ出力
      logging: {
        s3: true,
      },
    });

    // Wave 1: Dev環境
    const devWave = pipeline.addWave('Dev');
    const devStage = new ApplicationStage(
      this,
      'Dev',
      {
        env: {
          account: '111111111111', // Dev Account ID
          region: 'us-east-1',
        },
        stageName: 'dev',
      }
    );
    devWave.addStage(devStage);

    // Smoke Tests in Dev
    devWave.addPost(
      new pipelines.ShellStep('SmokeTests_Dev', {
        commands: [
          'npm run test:smoke',
        ],
        envFromCfnOutputs: {
          API_ENDPOINT: devStage.apiEndpointOutput,
        },
      })
    );

    // Wave 2: Staging環境
    const stagingWave = pipeline.addWave('Staging');
    const stagingStage = new ApplicationStage(
      this,
      'Staging',
      {
        env: {
          account: '222222222222', // Staging Account ID
          region: 'us-east-1',
        },
        stageName: 'staging',
      }
    );
    stagingWave.addStage(stagingStage);

    // Integration Tests
    stagingWave.addPost(
      new pipelines.ShellStep('IntegrationTests', {
        commands: [
          'npm run test:integration',
        ],
        envFromCfnOutputs: {
          STAGING_ENDPOINT: stagingStage.apiEndpointOutput,
        },
      })
    );

    // Manual Approval
    stagingWave.addPost(
      new pipelines.ManualApprovalStep('ApproveProduction')
    );

    // Wave 3: Production環境(マルチリージョン)
    const prodWave = pipeline.addWave('Production');
    
    // us-east-1
    const prodEastStage = new ApplicationStage(
      this,
      'ProdEast',
      {
        env: {
          account: '333333333333', // Prod Account ID
          region: 'us-east-1',
        },
        stageName: 'prod-east',
      }
    );
    prodWave.addStage(prodEastStage);

    // us-west-2(並列実行)
    const prodWestStage = new ApplicationStage(
      this,
      'ProdWest',
      {
        env: {
          account: '333333333333', // Prod Account ID
          region: 'us-west-2',
        },
        stageName: 'prod-west',
      }
    );
    prodWave.addStage(prodWestStage);

    // Production後のヘルスチェック
    prodWave.addPost(
      new pipelines.ShellStep('ProductionHealthCheck', {
        commands: [
          'npm run test:health-check',
        ],
        envFromCfnOutputs: {
          PROD_EAST_ENDPOINT: prodEastStage.apiEndpointOutput,
          PROD_WEST_ENDPOINT: prodWestStage.apiEndpointOutput,
        },
      })
    );
  }
}

ステップ2:アプリケーションスタック

import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecr from 'aws-cdk-lib/aws-ecr';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';

export interface ApplicationStageProps extends cdk.StackProps {
  stageName: string;
}

export class ApplicationStage extends cdk.Stage {
  public readonly apiEndpointOutput: cdk.CfnOutput;

  constructor(scope: cdk.App, id: string, props: ApplicationStageProps) {
    super(scope, id, props);

    const stack = new ApplicationStack(this, 'AppStack', {
      stageName: props.stageName,
    });

    this.apiEndpointOutput = stack.apiEndpointOutput;
  }
}

class ApplicationStack extends cdk.Stack {
  public readonly apiEndpointOutput: cdk.CfnOutput;

  constructor(scope: cdk.Construct, id: string, props: ApplicationStageProps) {
    super(scope, id);

    // VPC構築
    const vpc = new ec2.Vpc(this, 'AppVpc', {
      maxAzs: 2,
      natGateways: 1,
    });

    // ECS Cluster
    const cluster = new ecs.Cluster(this, 'AppCluster', {
      vpc,
    });

    // Fargate Service
    const taskDefinition = new ecs.FargateTaskDefinition(
      this,
      'TaskDef',
      {
        memoryLimitMiB: 512,
        cpu: 256,
      }
    );

    const container = taskDefinition.addContainer('AppContainer', {
      image: ecs.ContainerImage.fromRegistry('nginx:latest'),
      containerPort: 80,
      logging: ecs.LogDriver.awsLogs({
        streamPrefix: 'cdk-app',
      }),
    });

    const service = new ecs.FargateService(this, 'Service', {
      cluster,
      taskDefinition,
      desiredCount: 2,
      circuitBreaker: {
        rollback: true,
      },
    });

    // ALB
    const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
      vpc,
      internetFacing: true,
    });

    const listener = alb.addListener('Listener', {
      port: 80,
    });

    listener.addTargets('Targets', {
      port: 80,
      targets: [service],
      healthCheck: {
        path: '/',
        interval: cdk.Duration.seconds(30),
      },
    });

    this.apiEndpointOutput = new cdk.CfnOutput(this, 'APIEndpoint', {
      value: alb.loadBalancerDnsName,
      exportName: `${this.stackName}-api-endpoint`,
    });
  }
}

AWS構成図:CDK Pipelinesアーキテクチャ

graph TB
    subgraph "ToolsAccount[Tools Account]"
        GitHub["GitHub Repository"]
        CodeStarConn["CodeStar Connection"]
        CodePipeline["CodePipeline"]
        CodeBuild["CodeBuild Synth"]
        S3Artifact["S3 Artifact Store"]
        CloudFormation["CloudFormation<br/>Self-Mutation"]
    end
    
    subgraph "DevAccount[Dev Account]"
        DevVPC["VPC"]
        DevECS["ECS/Fargate"]
        DevALB["ALB"]
        DevLogs["CloudWatch Logs"]
        DevSmoke["Smoke Tests<br/>Lambda"]
    end
    
    subgraph "StagingAccount[Staging Account]"
        StagingVPC["VPC"]
        StagingECS["ECS/Fargate"]
        StagingALB["ALB"]
        StagingInteg["Integration Tests<br/>Lambda"]
        Approval["Manual Approval"]
    end
    
    subgraph "ProdAccount[Production Account]"
        subgraph "EastRegion[us-east-1]"
            ProdVPC1["VPC"]
            ProdECS1["ECS/Fargate"]
            ProdALB1["ALB"]
            ProdDB1["RDS Aurora<br/>Primary"]
            ProdHealth1["Health Check"]
        end
        
        subgraph "WestRegion[us-west-2]"
            ProdVPC2["VPC"]
            ProdECS2["ECS/Fargate"]
            ProdALB2["ALB"]
            ProdDB2["RDS Aurora<br/>Replica"]
            ProdHealth2["Health Check"]
        end
    end
    
    GitHub -->|Webhook| CodeStarConn
    CodeStarConn -->|Source| CodePipeline
    CodePipeline -->|Trigger| CodeBuild
    CodeBuild -->|Output| S3Artifact
    S3Artifact -->|Update Pipeline| CloudFormation
    CloudFormation -->|Deploy| DevVPC
    DevECS -->|Endpoint| DevALB
    DevALB -->|Test| DevSmoke
    DevSmoke -->|Pass| StagingVPC
    StagingECS -->|Endpoint| StagingALB
    StagingALB -->|Test| StagingInteg
    StagingInteg -->|Pass| Approval
    Approval -->|Approved| ProdVPC1
    ProdECS1 -->|Endpoint| ProdALB1
    ProdALB1 -->|Sync| ProdDB1
    ProdALB1 -->|Health| ProdHealth1
    ProdVPC1 -->|Replication| ProdVPC2
    ProdECS2 -->|Endpoint| ProdALB2
    ProdALB2 -->|Replica| ProdDB2
    ProdALB2 -->|Health| ProdHealth2

CDK Aspects によるセキュリティ検証の自動化

2026年版CDK Pipelinesでは、Aspectsを活用したセキュリティポリシー検証が必須です。以下は実装例です:

import * as cdk from 'aws-cdk-lib';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Aspects, IAspect, IConstruct } from 'aws-cdk-lib';
import * as nag from 'cdk-nag';

// cdk-nagによるセキュリティ検証
export function addSecurityAspects(stack: cdk.Stack): void {
  // AWS Solutions Checks
  Aspects.of(stack).add(
    new nag.AwsSolutionsChecks({
      reports: true,
      verbose: true,
    })
  );

  // HIPAA対応チェック
  Aspects.of(stack).add(
    new nag.HIPAASecurityChecks({
      reports: true,
    })
  );

  // PCI DSS対応チェック
  Aspects.of(stack).add(
    new nag.PCI_DSS_321_Checks({
      reports: true,
    })
  );

  // カスタムセキュリティチェック
  Aspects.of(stack).add(new EnforcedEncryptionAspect());
  Aspects.of(stack).add(new PublicAccessAspect());
}

// カスタムAspect:暗号化の強制
class EnforcedEncryptionAspect implements IAspect {
  public visit(node: IConstruct): void {
    if (
      node instanceof iam.Role &&
      node.node.path.includes('Pipeline')
    ) {
      // パイプライン関連のIAMロールに対して最小権限を適用
      node.addManagedPolicy(
        iam.ManagedPolicy.fromAwsManagedPolicyName(
          'CloudWatchLogsFullAccess'
        )
      );
    }
  }
}

// カスタムAspect:パブリックアクセス制限
class PublicAccessAspect implements IAspect {
  public visit(node: IConstruct): void {
    // VPCエンドポイントの設定を検証
    if (node.node.id.includes('LoadBalancer')) {
      cdk.Annotations.of(node).addWarning(
        'Load balancerのパブリックアクセスを確認してください'
      );
    }
  }
}

デプロイメント戦略の比較

戦略特徴推奨用途リスク
ブルーグリーン旧版と新版を並行実行、トラフィック切り替え本番環境への大規模変更リソース消費2倍
カナリアリリース小規模トラフィックで検証後、段階的切り替え新機能の品質検証ルーティング複雑化
ローリングデプロイインスタンスを順次更新継続的な小規模更新一時的なキャパシティ低下
イミュータブル新しいインスタンス群に完全切り替えマイクロサービス初期デプロイ時間が長い

CI/CDパイプラインのベストプラクティス

1. ソースコード管理

graph LR
    A["main"] -->|Protected Branch| B["Code Review<br/>Approval"]
    C["feature/*"] -->|PR| D["Automated Tests"]
    D -->|Pass| B
    B -->|Merge| A
    A -->|Trigger| E["Pipeline Execution"]

2. テスト戦略の階層化

graph TB
    A["コミット"] -->|Push| B["Unit Tests"]
    B -->|Pass| C["Integration Tests"]
    C -->|Pass| D["Smoke Tests<br/>Dev環境"]
    D -->|Pass| E["E2E Tests<br/>Staging環境"]
    E -->|Pass| F["カナリアリリース<br/>Prod環境"]
    F -->|Monitor| G["本番環境"]
    
    style B fill:#e1f5ff
    style C fill:#e1f5ff
    style D fill:#fff3e0
    style E fill:#fff3e0
    style F fill:#ffebee
    style G fill:#ffebee

3. 承認ゲートの設計

sequenceDiagram
    participant Dev as Dev環境
    participant Staging as Staging環境
    participant Approval as 手動承認
    participant Prod as Prod環境
    participant Monitor as 監視

    Dev->>Dev: Smoke Tests
    Dev->>Staging: Deploy
    Staging->>Staging: Integration Tests
    Staging->>Approval: 承認リクエスト
    Approval->>Approval: レビュー・チェック
    Approval->>Prod: 承認→デプロイ
    Prod->>Monitor: ヘルスチェック実行
    Monitor->>Monitor: アラート設定確認

IAMロール設定のセキュリティベストプラクティス

import * as iam from 'aws-cdk-lib/aws-iam';
import * as cdk from 'aws-cdk-lib';

export class PipelineIAMConfiguration {
  static createCrossAccountDeploymentRole(
    stack: cdk.Stack,
    targetAccount: string,
    pipelineArn: string
  ): iam.IRole {
    // ターゲットアカウントのデプロイロールを作成
    const deployRole = new iam.Role(stack, 'CrossAccountDeployRole', {
      assumedBy: new iam.ArnPrincipal(pipelineArn),
      description: 'Cross-account deployment role for CDK Pipelines',
      maxSessionDuration: cdk.Duration.hours(1),
    });

    // 最小権限の原則に従う
    deployRole.addToPrincipalPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: [
          'cloudformation:CreateStack',
          'cloudformation:UpdateStack',
          'cloudformation:DescribeStacks',
          'cloudformation:GetTemplate',
        ],
        resources: [
          `arn:aws:cloudformation:*:${targetAccount}:stack/*`,
        ],
      })
    );

    // IAM権限は極めて限定的
    deployRole.addToPrincipalPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: [
          'iam:PassRole',
        ],
        resources: [
          `arn:aws:iam::${targetAccount}:role/cdk-*`,
        ],
        conditions: {
          StringEquals: {
            'iam:PassedToService': [
              'cloudformation.amazonaws.com',
              'ecs-tasks.amazonaws.com',
            ],
          },
        },
      })
    );

    // S3アーティファクトへのアクセス
    deployRole.addToPrincipalPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: [
          's3:GetObject',
          's3:GetObjectVersion',
        ],
        resources: [
          `arn:aws:s3:::cdk-artifacts-*/*`,
        ],
      })
    );

    return deployRole;
  }
}

トラブルシューティング:一般的な問題と解決方法

問題原因解決方法
「Access Denied」エラーCross-account IAM権限が不足しているCloudTrail/CloudWatch Logsで権限を確認し、IAMポリシーを追加
CloudFormationスタック作成失敗リソース依存関係の不正、テンプレートエラーcdk diffで差分を確認、cdk synthでテンプレートを検証
デプロイメント時間が長い大量のリソース作成、キャッシング未設定FileCache.npm()を有効化、不要なWaveを削除
Webhookが機能しないCodeStar接続が未認可状態AWS Consoleで接続ステータスを確認、再認可を実施
Self-mutationループパイプリーン定義に無限ループパイプライン出力をアーティファクトから除外

トラブルシューティングの実装例

// CloudWatch Logsを使用した詳細なログ出力
import * as logs from 'aws-cdk-lib/aws-logs';

export function enableDetailedLogging(
  stack: cdk.Stack,
  pipeline: pipelines.CodePipeline
): void {
  // CodePipelineのログを有効化
  const logGroup = new logs.LogGroup(stack, 'PipelineLogGroup', {
    logGroupName: '/aws/codepipeline/cdk-pipelines-2026',
    retention: logs.RetentionDays.ONE_MONTH,
    removalPolicy: cdk.RemovalPolicy.DESTROY,
  });

  // CloudTrailの設定
  const trail = new cdk.aws_cloudtrail.Trail(stack, 'PipelineTrail', {
    bucket: new cdk.aws_s3.Bucket(stack, 'TrailBucket', {
      blockPublicAccess: cdk.aws_s3.BlockPublicAccess.BLOCK_ALL,
      encryption: cdk.aws_s3.BucketEncryption.S3_MANAGED,
    }),
    isMultiRegionTrail: true,
    includeGlobalServiceEvents: true,
  });

  // CloudWatch アラーム設定
  new cdk.aws_cloudwatch.Alarm(stack, 'PipelineFailureAlarm', {
    metric: new cdk.aws_cloudwatch.Metric({
      namespace: 'AWS/CodePipeline',
      metricName: 'PipelineExecutionFailure',
      statistic: 'Sum',
      period: cdk.Duration.minutes(5),
    }),
    threshold: 1,
    evaluationPeriods: 1,
    alarmDescription: 'Alert when CDK Pipeline fails',
  });
}

本番環境デプロイ前チェックリスト

graph TD
    A["デプロイ準備"] --> B{"ソースコード<br/>確認"}
    B -->|Pass| C{"テスト実行<br/>確認"}
    B -->|Fail| Z["修正が必要"]
    C -->|Pass| D{"セキュリティ<br/>スキャン"}
    C -->|Fail| Z
    D -->|Pass| E{"リソース<br/>容量確認"}
    D -->|Fail| Z
    E -->|Pass| F{"バックアップ<br/>確認"}
    E -->|Fail| Z
    F -->|Pass| G{"ロールバック<br/>計画"}
    F -->|Fail| Z
    G -->|Pass| H["本番デプロイ<br/>実行"]
    G -->|Fail| Z
    H -->|Success| I["監視開始"]
    H -->|Failure| J["ロールバック実行"]
    J --> K["原因調査"]
    
    style A fill:#e1f5ff
    style Z fill:#ffcdd2
    style I fill:#c8e6c9
    style K fill:#fff9c4

まとめ

2026年版CDK Pipelinesは、マルチアカウント・マルチリージョン対応のCI/CD構築を以下の観点で実現します:

  • セキュリティ:最小権限の原則に基づく自動IAM設定
  • 信頼性:多段階テスト、カナリアリリース、自動ロールバック
  • スケーラビリティ:並列デプロイメント、動的Wave制御
  • 可視性:CloudWatch Logsによる詳細な監視とアラート

これらの機能を組み合わせることで、エンタープライズグレードのCI/CD基盤を構築できます。

U

Untanbaby

ソフトウェアエンジニア|AWS / クラウドアーキテクチャ / DevOps

10年以上のIT実務経験をもとに、現場で使える技術情報を発信しています。 記事の誤りや改善点があればお問い合わせからお気軽にご連絡ください。

関連記事