📝

memo

2024/12/21に公開

CDKプロジェクト初期設定

cdk init app --language typescript
import * as fs from 'fs';

//IAM Access Analyzerで生成したJSON形式のIAMポリシーは policy.json にコピペしておく
//このtsファイルを実行すると、cdkPolicy.tsというファイルが生成されるので、そこに記載されているコードをCDK本体にいい感じにマージする

//IAM Access Analyzerで生成したJSON形式のIAMポリシーをCDKのコードに変換する関数
function convertJsonPolicyToCdkCode(jsonPolicy: any): string {
  const policyStatements = jsonPolicy.Statement.map((statement: any) => {
    // Actionsが配列でない場合は配列に変換
    const actions = statement.Action ? (Array.isArray(statement.Action) ? statement.Action : [statement.Action]) : [];
    
    // NotActionsが配列でない場合は配列に変換
    const notActions = statement.NotAction ? (Array.isArray(statement.NotAction) ? statement.NotAction : [statement.NotAction]) : [];
    
    // Resourcesが配列でない場合は配列に変換
    const resources = Array.isArray(statement.Resource) ? statement.Resource : [statement.Resource];
    
    // NotResourcesが配列でない場合は配列に変換
    const notResources = statement.NotResource ? (Array.isArray(statement.NotResource) ? statement.NotResource : [statement.NotResource]) : [];
    
    // PolicyStatementを生成
    let statementCode = `  new iam.PolicyStatement({\n      effect: iam.Effect.${statement.Effect.toUpperCase()},\n`;
    
    // actionsが存在する場合のみ追加
    if (actions.length > 0) {
      statementCode += `      actions: ${JSON.stringify(actions)},\n`;
    }
    
    // notActionsが存在する場合のみ追加
    if (notActions.length > 0) {
      statementCode += `      notActions: ${JSON.stringify(notActions)},\n`;
    }
    
    // resourcesが存在する場合は必ず追加
    statementCode += `      resources: ${JSON.stringify(resources)},\n`;
    
    // notResourcesが存在する場合のみ追加
    if (notResources.length > 0) {
      statementCode += `      notResources: ${JSON.stringify(notResources)},\n`;
    }
    
    // conditionsが存在する場合のみ追加
    if (statement.Condition) {
      statementCode += `      conditions: ${JSON.stringify(statement.Condition)},\n`;
    }
    
    statementCode += `    })`;
    
    return statementCode;
  }).join(',\n  ');

  // 最終的にManagedPolicyを作成するコードを生成
  return `const iamPolicydocument = new iam.PolicyDocument({\n  statements: [\n  ${policyStatements}\n  ]\n});\nconst iamManagedPolicy = new iam.ManagedPolicy(this, 'iamManagedPolicy', {\n  document: iamPolicydocument,\n});`;
}

// JSONポリシーをファイルから読み込む
const jsonPolicy = fs.readFileSync('policy.json', 'utf8');
const parsedJsonPolicy = JSON.parse(jsonPolicy);

// CDKコードを生成
const cdkCode = convertJsonPolicyToCdkCode(parsedJsonPolicy);

// 生成されたCDKコードを表示
fs.writeFileSync('cdkPolicy.ts', cdkCode);

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as iam from 'aws-cdk-lib/aws-iam'
import { userInfo } from 'os';

//iam user list
const managerUserNames = ['tom', 'john'];
const contributorUserNames = ['maria', 'sofia'];

export class CdkIamStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    //create iam user group: manager
    const iamUserGroupManager = new iam.Group(this, 'iamUserGroupManager', {
      groupName: "pan-iam-user-group-manager"
    });

    //create iam user group: contributor
    const iamUserGroupContributor = new iam.Group(this, 'iamUserGroupContributor', {
      groupName: "pan-iam-user-group-contributor"
    });


    //create iam users: manager
    const managerUsers: iam.User[] = managerUserNames.map(userName => {
      return new iam.User(this, `user-${userName}`, {
        userName: userName
      });
    });

    //create iam users: contributor
    const contributorUsers: iam.User[] = contributorUserNames.map(userName => {
      return new iam.User(this, `user-${userName}`, {
        userName: userName
      });
    });

    //create iam role: switch role for manager
    const iamRoleManager = new iam.Role(this, 'iamRoleManager', {
      assumedBy: new iam.CompositePrincipal(
        ...managerUsers.map(user => new iam.ArnPrincipal(user.userArn)),
        new iam.ServicePrincipal('cloudformation.amazonaws.com')
      ),
      roleName: 'pan-iam-role-switch-manager',
    });

    //create customer managed policy document: assumerole manager by IAM Access Analyzer
    const iamPolicyDocumentAssumeRole = new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["sts:AssumeRole"],
          resources: [iamRoleManager.roleArn],
        })
      ]
    });
    const iamManagedPolicyAssumeRoleManager = new iam.ManagedPolicy(this, 'iamManagedPolicyAssumeRoleManager', {
      document: iamPolicyDocumentAssumeRole,
    });


    //create iam role: switch role for contributor
    const iamRoleContributor = new iam.Role(this, 'iamRoleContributor', {
      assumedBy: new iam.CompositePrincipal(
        ...contributorUsers.map(user => new iam.ArnPrincipal(user.userArn)),
        new iam.ServicePrincipal('cloudformation.amazonaws.com')
      ),
      roleName: 'pan-iam-role-switch-contributor',
    });

    //create customer managed policy document: assumerole contributor by IAM Access Analyzer
    const iamPolicyDocumentAssumeRoleContributor = new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["sts:AssumeRole"],
          resources: [iamRoleContributor.roleArn],
        })
      ]
    });
    const iamManagedPolicyAsumeRoleContributor = new iam.ManagedPolicy(this, 'iamManagedPolicyAsumeRoleContributor', {
      document: iamPolicyDocumentAssumeRoleContributor,
    });


    //create customer managed policy document: forceMFA by IAM Access Analyzer
    const iamPolicyDocumnetForceMFA = new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["iam:GetAccountPasswordPolicy","iam:ListVirtualMFADevices"],
          resources: ["*"],
        }),
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["iam:ChangePassword","iam:Getuser"],
          resources: ["arn:aws:iam::*:user/${aws:username}"],
        }),
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["iam:DeactivateMFADevice","iam:EnableMFADevice","iam:ListMFADevices","iam:ResyncMFADevice"],
          resources: ["arn:aws:iam::*:user/${aws:username}"],
        }),
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["iam:CreateVirtualMFADevice","iam:DeleteVirtualMFADevice"],
          resources: ["arn:aws:iam::*:mfa/${aws:username}"],
        }),
        new iam.PolicyStatement({
          effect: iam.Effect.DENY,
          notActions: ["iam:CreateVirtualMFADevice","iam:EnableMFADevice","iam:GetUser","iam:ListMFADevices","iam:ListVirtualMFADevices","iam:ResyncMFADevice","sts:GetSessionToken","iam:ChangePassword","iam:CreateLoginProfile","iam:UpdateLoginProfile"],
          resources: ["*"],
          conditions: {"BoolIfExists":{"aws:MultiFactorAuthPresent":"false"}},
        })
      ]
    });
    const iamManagedPolicyForceMFA = new iam.ManagedPolicy(this, 'iamManagedPolicyForceMFA', {
      document: iamPolicyDocumnetForceMFA,
    });

    //attach Maneged Policy to group
    iamUserGroupManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
    iamUserGroupManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSBillingConductorFullAccess'));
    iamUserGroupManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSCodeCommitFullAccess'));
    iamUserGroupManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('IAMFullAccess'));
    iamUserGroupManager.addManagedPolicy(iamManagedPolicyForceMFA);
    iamUserGroupManager.addManagedPolicy(iamManagedPolicyAssumeRoleManager);

    iamUserGroupContributor.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('ReadOnlyAccess'));
    iamUserGroupContributor.addManagedPolicy(iamManagedPolicyForceMFA);
    iamUserGroupContributor.addManagedPolicy(iamManagedPolicyAsumeRoleContributor);

    //attach Managed Policy to Role
    iamRoleManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
    iamRoleManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSBillingConductorFullAccess'));
    iamRoleManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSCodeCommitFullAccess'));
    iamRoleManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('IAMFullAccess'));

    iamRoleContributor.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('ReadOnlyAccess'));
  }
}
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as iam from 'aws-cdk-lib/aws-iam'
import { userInfo } from 'os';

//iam user list
const managerUserNames = ['tom', 'john', 'nana'];
const contributorUserNames = ['maria', 'sofia'];
const cdkDeployUserNames = ['renta', 'norenta']

export class CdkIamStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    //ユーザをインポートした際にはタグをつけることはCDKではできない。iam.Userで作成する際にタグを追加する必要がある
    /*
    // IAMユーザーを作成し、タグを追加
    const user = new iam.User(this, 'YamazakiUser', {
      userName: 'ymz-manager',
      tags: {
        'aws/PrincipalTag/CdkDeploy': 'Enable', // タグを指定
      },
    });
    */

    /*
    //create cdk user
    const CdkDeployUser = new iam.User(this, 'CdkDeployUser', {
      userName: 'ymz-cdk-deploy',
    })
    //タグ付け
    cdk.Tags.of(CdkDeployUser).add('aws/PrincipalTag/CdkDeploy', 'Enable');
    */


    //create iam user group: cdk
    const iamUserGroupCdkDeploy = new iam.Group(this, 'iamUserGroupCdkDeploy', {
      groupName: "pan-iam-user-group-cdk"
    });

    //create iam user group: manager
    const iamUserGroupManager = new iam.Group(this, 'iamUserGroupManager', {
      groupName: "pan-iam-user-group-manager"
    });

    //create iam user group: contributor
    const iamUserGroupContributor = new iam.Group(this, 'iamUserGroupContributor', {
      groupName: "pan-iam-user-group-contributor"
    });


    //create iam users: manager
    const managerUsers: iam.User[] = managerUserNames.map(userName => {
      return new iam.User(this, `user-${userName}`, {
        userName: userName
      });
    });

    //create iam users: contributor
    const contributorUsers: iam.User[] = contributorUserNames.map(userName => {
      return new iam.User(this, `user-${userName}`, {
        userName: userName
      });
    });

    //create iam users: cdk
    const CdkDeployUsers: iam.User[] = cdkDeployUserNames.map(userName => {
      return new iam.User(this, `user-${userName}`, {
        userName: userName
      });
    });
    CdkDeployUsers.map(user => {
      cdk.Tags.of(user).add('CdkDeploy', 'Enable');
    })

    //create iam role: switch role for manager
    //ここ!タグ制御!信頼ポリシーで設定するのが楽
    const iamRoleCdkDeploy = new iam.Role(this, 'iamRoleCdkDeploy', {
      roleName: 'pan-iam-role-switch-cdk-deploy',
      assumedBy: new iam.CompositePrincipal(
        ...CdkDeployUsers.map(user => new iam.ArnPrincipal(user.userArn).withConditions({
          StringLike:{
            'aws:RequestTag/CdkDeploy': 'Enable',
          },
        })),
      )
    });

    //create customer managed policy document: assumerole CDK deplot role
    const iamPolicyDocumentAssumeRoleCdkCdployRole = new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["sts:AssumeRole"],
          resources: [iamRoleCdkDeploy.roleArn],
        })
      ]
    });
    const iamManagedPolicyAsumeRoloCdkDeploy = new iam.ManagedPolicy(this, 'iamManagedPolicyAsumeRoloCdkDeploy', {
      document: iamPolicyDocumentAssumeRoleCdkCdployRole,
    });


    //create iam role: switch role for manager
    const iamRoleManager = new iam.Role(this, 'iamRoleManager', {
      assumedBy: new iam.CompositePrincipal(
        ...managerUsers.map(user => new iam.ArnPrincipal(user.userArn)),
        new iam.ServicePrincipal('cloudformation.amazonaws.com')
      ),
      roleName: 'pan-iam-role-switch-manager',
    });

    //create customer managed policy document: assumerole manager by IAM Access Analyzer
    const iamPolicyDocumentAssumeRole = new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["sts:AssumeRole"],
          resources: [iamRoleManager.roleArn],
        })
      ]
    });
    const iamManagedPolicyAssumeRoleManager = new iam.ManagedPolicy(this, 'iamManagedPolicyAssumeRoleManager', {
      document: iamPolicyDocumentAssumeRole,
    });


    //create iam role: switch role for contributor
    const iamRoleContributor = new iam.Role(this, 'iamRoleContributor', {
      assumedBy: new iam.CompositePrincipal(
        ...contributorUsers.map(user => new iam.ArnPrincipal(user.userArn)),
        new iam.ServicePrincipal('cloudformation.amazonaws.com')
      ),
      roleName: 'pan-iam-role-switch-contributor',
    });


    //create customer managed policy document: assumerole contributor by IAM Access Analyzer
    const iamPolicyDocumentAssumeRoleContributor = new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["sts:AssumeRole"],
          resources: [iamRoleContributor.roleArn],
        })
      ]
    });
    const iamManagedPolicyAsumeRoleContributor = new iam.ManagedPolicy(this, 'iamManagedPolicyAsumeRoleContributor', {
      document: iamPolicyDocumentAssumeRoleContributor,
    });


    //create customer managed policy document: forceMFA by IAM Access Analyzer
    const iamPolicyDocumnetForceMFA = new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["iam:GetAccountPasswordPolicy","iam:ListVirtualMFADevices"],
          resources: ["*"],
        }),
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["iam:ChangePassword","iam:Getuser"],
          resources: ["arn:aws:iam::*:user/${aws:username}"],
        }),
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["iam:DeactivateMFADevice","iam:EnableMFADevice","iam:ListMFADevices","iam:ResyncMFADevice"],
          resources: ["arn:aws:iam::*:user/${aws:username}"],
        }),
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["iam:CreateVirtualMFADevice","iam:DeleteVirtualMFADevice"],
          resources: ["arn:aws:iam::*:mfa/${aws:username}"],
        }),
        new iam.PolicyStatement({
          effect: iam.Effect.DENY,
          notActions: ["iam:CreateVirtualMFADevice","iam:EnableMFADevice","iam:GetUser","iam:ListMFADevices","iam:ListVirtualMFADevices","iam:ResyncMFADevice","sts:GetSessionToken","iam:ChangePassword","iam:CreateLoginProfile","iam:UpdateLoginProfile"],
          resources: ["*"],
          conditions: {"BoolIfExists":{"aws:MultiFactorAuthPresent":"false"}},
        })
      ]
    });
    const iamManagedPolicyForceMFA = new iam.ManagedPolicy(this, 'iamManagedPolicyForceMFA', {
      document: iamPolicyDocumnetForceMFA,
    });

    //attach Maneged Policy to group
    iamUserGroupManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
    iamUserGroupManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSBillingConductorFullAccess'));
    iamUserGroupManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSCodeCommitFullAccess'));
    iamUserGroupManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('IAMFullAccess'));
    iamUserGroupManager.addManagedPolicy(iamManagedPolicyForceMFA);
    iamUserGroupManager.addManagedPolicy(iamManagedPolicyAssumeRoleManager);

    iamUserGroupContributor.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('ReadOnlyAccess'));
    iamUserGroupContributor.addManagedPolicy(iamManagedPolicyForceMFA);
    iamUserGroupContributor.addManagedPolicy(iamManagedPolicyAsumeRoleContributor);

    iamUserGroupCdkDeploy.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
    iamUserGroupCdkDeploy.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSBillingConductorFullAccess'));
    iamUserGroupCdkDeploy.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSCodeCommitFullAccess'));
    iamUserGroupCdkDeploy.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('IAMFullAccess'));
    iamUserGroupCdkDeploy.addManagedPolicy(iamManagedPolicyForceMFA);
    iamUserGroupCdkDeploy.addManagedPolicy(iamManagedPolicyAsumeRoloCdkDeploy);

    //attach Managed Policy to Role
    iamRoleManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
    iamRoleManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSBillingConductorFullAccess'));
    iamRoleManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSCodeCommitFullAccess'));
    iamRoleManager.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('IAMFullAccess'));

    iamRoleContributor.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('ReadOnlyAccess'));

  }
}


Discussion