SecretもPulumiで使いこなしたい! PulumiのSecurityを試してみよう

2023年5月26日(金)
大関 研丞 (Kenneth Ozeki)
第4回となる今回は、PulumiのSecurityについて解説し、ハンズオンではPulumiによる暗号化処理を行い、AWS SecretManagerを利用したRDS接続する流れを実践していきます。

Secretリソースのデプロイ

実際にRDSのユーザーパスワードをStack設定ファイルに追加し、secretリソースを作成します。

  1. 「secret」ディレクトリのPulumi Program「__main__.py」を以下に書き換えます。
    import pulumi
    import pulumi_aws as aws
    
    # パスワードを取得する
    password = pulumi.Config().get_secret("my_password")
    
    # Secret Manager Secretの作成
    secret = aws.secretsmanager.Secret(
        "db-user-secret",
        name="db-user-secret",
    )
    
    # Secret Manager Secret Versionの作成
    secret_version = aws.secretsmanager.SecretVersion(
        "db-user-secret-version",
        secret_id=secret.id,
        secret_string=pulumi.Output.all(password).apply(lambda args: f"{{¥"username¥": ¥"my_username¥", ¥"password¥": ¥"{args[0]}¥"}}"),
    )
    
    # secret idをエクスポート
    pulumi.export('secret_id', secret.id)
    【Secretディレクトリ Pulumi Program(__main__.py)】

    コードのポイントは、
    • 「pulumi.Config().get_secret("my_password")」でStack設定ファイルの「my_password」をsecret値で取得し「password」変数に格納
    • 「secret_string=pulumi.Output.all(password).apply(***)」でpassword変数から取得したkey「my_password」のvalueを取り出し「username」とセットでjson形式でクレデンシャルを作成。Stack設定ファイルの情報を格納したpassword変数は「Output[T]」オブジェクトになるので「apply()」メソッドで情報を取得する。最終的にRDSインスタンスのクレデンシャルは「{"username": "my_username", "password": "12345678"}」になる
    になります。AWSリソースそれぞれのAPIリファレンスはこちらを参照ください。また「pulumi.get_stack()」や「pulumi.Config()」など、Pulumi Stack関連のConfigurationの取得に関してはこちらを参照ください。
  2. 「secret.dev」Stackを「pulumi up」でデプロイします。
    $ pulumi up     
    Previewing update (secret.dev)
    
    View Live: https://app.pulumi.com/***/pulumi-security/secret.dev/previews/5760bd11-ca69-48d8-b5f1-***
    
         Type                                 Name                        Plan       
     +   pulumi:pulumi:Stack                  pulumi-security-secret.dev  create     
     +   ├─ aws:secretsmanager:Secret         rds-secret                  create     
     +   └─ aws:secretsmanager:SecretVersion  rds-secret-version          create     
    
    
    Outputs:
        secret_id: output<string>
    
    Resources:
        + 3 to create
    
    Do you want to perform this update? yes
    Updating (secret.dev)
    
    View Live: https://app.pulumi.com/***/pulumi-security/secret.dev/updates/3
    
         Type                                 Name                        Status              
     +   pulumi:pulumi:Stack                  pulumi-security-secret.dev  created (3s)        
     +   ├─ aws:secretsmanager:Secret         rds-secret                  created (0.45s)     
     +   └─ aws:secretsmanager:SecretVersion  rds-secret-version          created (0.51s)     
    
    
    Outputs:
        secret_id: "arn:aws:secretsmanager:ap-northeast-1:926403295735:secret:rds-secret-ejrjbQ"
    
    Resources:
        + 3 created
    
    Duration: 6s
    デプロイ後、AWSマネジメントコンソールでsecretが作成されていることを確認できます。
    デプロイ後のStackのStateファイルでは、暗号化された状態でパスワードのリソース情報が格納されていることを確認できます。
    $ pulumi stack export | jq '.deployment.resources[] | select(.type == "aws:secretsmanager/secretVersion:SecretVersion")' | jq '.inputs'             
    
    {
      "__defaults": [],
      "secretId": "arn:aws:secretsmanager:ap-northeast-1:926403295735:secret:db-user-secret-rJyJ1T",
      "secretString": {
        "4dabf18193072939515e22adb298388d": "1b47061264138c4ac30d75fd1eb44270",
        "ciphertext": "AAABANwn/DfuYM+8egMVEVjNQcIQ8nopImow5DRsk7NaFHXSspztp58RgnSQsyXUm0HGkp22f8kL qXprQFF/kFdlhsluuUZsZ9PBjIZgepk9hbhB3RAtXhDYX5e3"
      }
    }

Networkリソースのデプロイ

EC2とRDSの配置に必要なVPC/サブネットなどのリソースや、セキュリティグループなどのNetwork関連のリソースを作成します。

  1. 「network」ディレクトリに移動し、Stackを「network.dev」に切り替えます。
    $ cd ../network
     
    $ pwd
    /***/pulumi-security/network
    
    $ pulumi stack select network.dev
    
    $ pulumi stack ls
    NAME         LAST UPDATE     RESOURCE COUNT  URL
    compute.dev  n/a             n/a             https://app.pulumi.com/***/pulumi-security/compute.dev
    network.dev*  n/a             n/a             https://app.pulumi.com/***/pulumi-security/network.dev
    secret.dev  23 minutes ago  4               https://app.pulumi.com/***/pulumi-security/secret.dev
  2. 「network」ディレクトリのPulumi Program「__main__.py」を以下に書き換えます。
    import pulumi
    import pulumi_aws as aws
    
    # VPCの作成
    vpc = aws.ec2.Vpc("my-vpc", cidr_block="10.0.0.0/16")
    
    # EC2用パブリックサブネットの作成
    public_subnet = aws.ec2.Subnet("my-public-subnet",
        vpc_id=vpc.id,
        cidr_block="10.0.0.0/24",
        availability_zone="ap-northeast-1a",
        map_public_ip_on_launch=True,
    )
    
    # RDS用プライベートサブネットの作成(az: 1a)
    private_subnet_1a = aws.ec2.Subnet("my-private-subnet-1a",
        vpc_id=vpc.id,
        cidr_block="10.0.1.0/24",
        availability_zone="ap-northeast-1a",
    )
    
    # RDS用プライベートサブネットの作成(az: 1c)
    private_subnet_1c = aws.ec2.Subnet("my-private-subnet-1c",
        vpc_id=vpc.id,
        cidr_block="10.0.2.0/24",
        availability_zone="ap-northeast-1c",
    )
    
    # RDS用サブネットグループの作成
    rds_subnet_group = aws.rds.SubnetGroup("my-rds-subnet-group",
        subnet_ids=[private_subnet_1a.id, private_subnet_1c.id],
    )
    
    # インターネットゲートウェイの作成
    internet_gateway = aws.ec2.InternetGateway("my-internet-gateway", vpc_id=vpc.id)
    
    # パブリックルートテーブルの作成
    public_route_table = aws.ec2.RouteTable("my-public-route-table",
        vpc_id=vpc.id,
        routes=[
            aws.ec2.RouteTableRouteArgs(
                cidr_block="0.0.0.0/0",
                gateway_id=internet_gateway.id,
            ),
        ],
    )
    
    # パブリックサブネットへの関連付け
    public_subnet_association = aws.ec2.RouteTableAssociation("my-public-subnet-association",
        subnet_id=public_subnet.id,
        route_table_id=public_route_table.id,
    )
    
    # EC2インスタンスのセキュリティグループの作成
    ec2_security_group = aws.ec2.SecurityGroup("my-ec2-security-group",
        vpc_id=vpc.id,
        ingress=[
            aws.ec2.SecurityGroupIngressArgs(
                protocol="tcp",
                from_port=22,
                to_port=22,
                cidr_blocks=["0.0.0.0/0"],
            ),
            aws.ec2.SecurityGroupIngressArgs(
                protocol="tcp",
                from_port=3306,
                to_port=3306,
                cidr_blocks=[private_subnet_1a.cidr_block, private_subnet_1c.cidr_block],
            ),
        ],
        egress=[
            aws.ec2.SecurityGroupEgressArgs(
                protocol="-1",
                from_port=0,
                to_port=0,
                cidr_blocks=["0.0.0.0/0"],
            ),
        ],
    )
    
    # RDSインスタンスのセキュリティグループの作成
    rds_security_group = aws.ec2.SecurityGroup("my-rds-security-group",
        vpc_id=vpc.id,
        ingress=[
            aws.ec2.SecurityGroupIngressArgs(
                protocol="tcp",
                from_port=3306,
                to_port=3306,
                cidr_blocks=[public_subnet.cidr_block],
            ),
        ],
        egress=[
            aws.ec2.SecurityGroupEgressArgs(
                protocol="tcp",
                from_port=3306,
                to_port=3306,
                cidr_blocks=[public_subnet.cidr_block],
            ),
        ],
    )
    
    # privateサブネットとRDS用サブネットグループのidをエクスポート
    pulumi.export("public_subnet_id", public_subnet.id)
    pulumi.export("rds_subnet_group_id", rds_subnet_group.id)
    
    # EC2/RDSそれぞれのセキュリティグループをエクスポート
    pulumi.export("ec2_security_group_id", ec2_security_group.id)
    pulumi.export("rds_security_group_id", rds_security_group.id)
    【networkディレクトリ Pulumi Program(__main__.py)】

    今回の検証に必要なNetworkリソース「VPC」「パブリック/プライベートサブネット」「インターネットゲートウェイ」「ルートテーブル」「ルートテーブルのサブネットへの紐付け」「EC2/RDS用のセキュリティグループ」を作成します。Pulumi Programの最後では、パブリック/プライベートサブネットとEC2/RDS用のセキュリティグループのidをOutputとして出力し、次の手順で実施するEC2やRDSの作成時に利用します。
  3. 「network.dev」Stackをデプロイします。
    $ pulumi up
         
    Previewing update (network.dev)
    
    View Live: https://app.pulumi.com/***/pulumi-security/network.dev/previews/9105ba1a-18c4-4ebd-a4d8-***
    
         Type                              Name                          Plan       
     +   pulumi:pulumi:Stack               pulumi-security-network.dev   create     
     +   ├─ aws:ec2:Vpc                    my-vpc                        create     
     +   ├─ aws:ec2:Subnet                 my-private-subnet-1a          create     
     +   ├─ aws:ec2:Subnet                 my-public-subnet              create     
     +   ├─ aws:ec2:Subnet                 my-private-subnet-1c          create     
     +   ├─ aws:ec2:InternetGateway        my-internet-gateway           create     
     +   ├─ aws:rds:SubnetGroup            my-rds-subnet-group           create     
     +   ├─ aws:ec2:SecurityGroup          my-ec2-security-group         create     
     +   ├─ aws:ec2:RouteTable             my-public-route-table         create     
     +   ├─ aws:ec2:SecurityGroup          my-rds-security-group         create     
     +   └─ aws:ec2:RouteTableAssociation  my-public-subnet-association  create     
    
    
    Outputs:
        ec2_security_group_id: output<string>
        public_subnet_id     : output<string>
        rds_security_group_id: output<string>
        rds_subnet_group_id  : output<string>
    
    Resources:
        + 11 to create
    
    Do you want to perform this update? yes
    Updating (network.dev)
    
    View Live: https://app.pulumi.com/***/pulumi-security/network.dev/updates/14
    
         Type                              Name                          Status              
     +   pulumi:pulumi:Stack               pulumi-security-network.dev   created (7s)        
     +   ├─ aws:ec2:Vpc                    my-vpc                        created (1s)        
     +   ├─ aws:ec2:Subnet                 my-public-subnet              created (0.70s)     
     +   ├─ aws:ec2:Subnet                 my-private-subnet-1c          created (1s)        
     +   ├─ aws:ec2:Subnet                 my-private-subnet-1a          created (1s)        
     +   ├─ aws:ec2:InternetGateway        my-internet-gateway           created (1s)        
     +   ├─ aws:rds:SubnetGroup            my-rds-subnet-group           created (1s)        
     +   ├─ aws:ec2:SecurityGroup          my-ec2-security-group         created (2s)        
     +   ├─ aws:ec2:SecurityGroup          my-rds-security-group         created (2s)        
     +   ├─ aws:ec2:RouteTable             my-public-route-table         created (1s)        
     +   └─ aws:ec2:RouteTableAssociation  my-public-subnet-association  created (0.69s)     
    
    
    Outputs:
        ec2_security_group_id: "sg-04980a9c997a5016f"
        public_subnet_id     : "subnet-06795a8bc15f25bbb"
        rds_security_group_id: "sg-075e0553fcdc72b15"
        rds_subnet_group_id  : "my-rds-subnet-group-2e8fb48"
    
    Resources:
        + 11 created
    
    Duration: 9s
著者
大関 研丞 (Kenneth Ozeki)
クリエーションライン株式会社 Data Platform Team
前職では保険や金融エンタープライズのミッションクリティカルシステム(オンプレミス、仮想サーバー、CDN等のインフラ系業務)の設計/構築を経験。クリエーションラインに転職後はクラウドエンジニアとしてGCP関連の案件でインフラの設計/構築、IaCやCI/CDを用いたDevOpsの導入、コンテナ(Kubernetes)基盤の構築、運用自動化ツールの作成などを担当。
クリエーションラインの技術ブログをチェック

連載バックナンバー

システム運用技術解説
第10回

Pulumiの最新機能「Pulumi ESC」を使ってみよう

2023/12/26
最終回となる今回は、2023年12月時点でリリースされている新機能の紹介と、その新機能の中から「Pulumi ESC」を用いたハンズオンを実践していきます。
システム運用技術解説
第9回

TerraformからPulumiへの移行

2023/11/28
第9回となる今回は、既にTerraformでAWS環境に作成されているリソースをPulumiへ移行するケースを想定して、CoexistenceとConversionのハンズオンを実践していきます
システム運用技術解説
第8回

既に存在するリソースをPulumiで管理してみよう

2023/10/19
第8回となる今回は、既にクラウド環境にデプロイされているリソースをPulumiで管理(import)する方法について、ハンズオンで実践していきます。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています