AWS CLIでスタックのアウトプットパラメータを取得する

2020.11.13

こんにちは、コンサル部の鈴木(純)です。

最近AWS CLIを使ってCloudFormationスタックのアウトプットパラメータを取得したことがあったので、メモとして共有します。

どんなときに便利か

私がAWS CLIを使ってCloudFormationスタックのアウトプットパラメータを取得しようと思ったのは、以下のような条件の場合でした。

  • 対象のリソースがCloudFormationで対応していない
  • 対象のリソースがAWS CLIでは作成できる
  • マネージメントコンソールからリソースを作成したくない
  • CloudFormationのスタックで作成したリソースを参照したい

多くのリソースに対応しているCloudFormationですが、全てのリソースに対応しているというわけではないので、どうしても対応できない部分はあります。私の場合はAD ConnectorがCloudFormationに対応していなかったので、事前にCloudFormationで作成したVPCやサブネットの情報を取得してAWS CLIで作成する方法を検討しました。

やってみる

それでは早速実際にCloudFormationのスタックを展開してAWS CLIでアウトプットしたパラメータを取得していきます。今回jsonの整形を行う部分では、AWS CLIオプションのqueryでもできるのですが、 使い方がよく分かっていないので jqで行っています。

実行環境

  • macOS Catalina 10.15.7
  • AWS CLI V2
  • jq 1.6

スタックの展開

単純にVPCとパブリックサブネット2つ、プライベートサブネットを2つを定義したNetworkStackを展開しています。

全部のテンプレートを載せると量が多いので、アウトプットしているパラメータだけ載せておきます。

Outputs:
  Vpc:
    Value: !Ref Vpc
    Export:
      Name: !Sub ${AWS::StackName}-Vpc

  PublicSubnetAZ1:
    Value: !Ref PublicSubnetAZ1
    Export:
      Name: !Sub ${AWS::StackName}-PublicSubnetAZ1
  PublicSubnetAZ2:
    Value: !Ref PublicSubnetAZ2
    Export:
      Name: !Sub ${AWS::StackName}-PublicSubnetAZ2
  PrivateSubnetAZ1:
    Value: !Ref PrivateSubnetAZ1
    Export:
      Name: !Sub ${AWS::StackName}-PrivateSubnetAZ1
  PrivateSubnetAZ2:
    Value: !Ref PrivateSubnetAZ2
    Export:
      Name: !Sub ${AWS::StackName}-PrivateSubnetAZ2

#Cidr output
  VpcCidr:
    Value: !Ref VpcCidr
    Export:
      Name: !Sub ${AWS::StackName}-VpcCidr
  PublicSubnetAZ1Cidr:
    Value: !Ref PublicSubnetAZ1Cidr
    Export:
      Name: !Sub ${AWS::StackName}-PublicSubnetAZ1Cidr
  PublicSubnetAZ2Cidr:
    Value: !Ref PublicSubnetAZ2Cidr
    Export:
      Name: !Sub ${AWS::StackName}-PublicSubnetAZ2Cidr
  PrivateSubnetAZ1Cidr:
    Value: !Ref PrivateSubnetAZ1Cidr
    Export:
      Name: !Sub ${AWS::StackName}-PrivateSubnetAZ1Cidr
  PrivateSubnetAZ2Cidr:
    Value: !Ref PrivateSubnetAZ2Cidr
    Export:
      Name: !Sub ${AWS::StackName}-PrivateSubnetAZ2Cidr

例えばVPCのIDを取得したい場合、CloudFormationの別スタックから参照するときはImportValueを使えばいいですが、今回はAWS CLIから取得する必要があります。

CloudFormationスタックからCLIで情報を取得する

CloudFormationのスタック情報を取得するAWS CLIはdescribe-stacksを使えば取得できます。

今回はスタックの名前はNetworkStackとしているので、オプションでスタック名を指定してあげましょう。実行すると以下のようなjsonのレスポンスが返ってきました。

$ aws cloudformation describe-stacks --stack-name NetworkStack 
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/NetworkStack/cdc61ce0-1d64-11eb-954e-0a683702510a",
            "StackName": "NetworkStack",
            "ChangeSetId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:changeSet/awscli-cloudformation-package-deploy-1604360434/4cd2f8d3-1e6b-4b63-be1c-c8641e8f982f",
            "Parameters": [
                {
                    "ParameterKey": "PublicSubnetAZ2Cidr",
                    "ParameterValue": "10.0.1.0/24"
                },
                {
                    "ParameterKey": "PrivateSubnetAZ2Cidr",
                    "ParameterValue": "10.0.3.0/24"
                },
                {
                    "ParameterKey": "VpcCidr",
                    "ParameterValue": "10.0.0.0/16"
                },
                {
                    "ParameterKey": "SystemName",
                    "ParameterValue": "test"
                },
                {
                    "ParameterKey": "Env",
                    "ParameterValue": "dev"
                },
                {
                    "ParameterKey": "PrivateSubnetAZ1Cidr",
                    "ParameterValue": "10.0.2.0/24"
                },
                {
                    "ParameterKey": "PublicSubnetAZ1Cidr",
                    "ParameterValue": "10.0.0.0/24"
                }
            ],
            "CreationTime": "2020-11-02T23:40:35.489000+00:00",
            "LastUpdatedTime": "2020-11-02T23:40:40.957000+00:00",
            "RollbackConfiguration": {},
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Capabilities": [
                "CAPABILITY_NAMED_IAM"
            ],
            "Outputs": [
                {
                    "OutputKey": "PublicSubnetAZ1",
                    "OutputValue": "subnet-0d83a103c6102239e",
                    "ExportName": "NetworkStack-PublicSubnetAZ1"
                },
                {
                    "OutputKey": "PublicSubnetAZ2Cidr",
                    "OutputValue": "10.0.1.0/24",
                    "ExportName": "NetworkStack-PublicSubnetAZ2Cidr"
                },
                {
                    "OutputKey": "PublicSubnetAZ2",
                    "OutputValue": "subnet-03da5606647c8e00d",
                    "ExportName": "NetworkStack-PublicSubnetAZ2"
                },
                {
                    "OutputKey": "PrivateSubnetAZ2Cidr",
                    "OutputValue": "10.0.3.0/24",
                    "ExportName": "NetworkStack-PrivateSubnetAZ2Cidr"
                },
                {
                    "OutputKey": "VpcCidr",
                    "OutputValue": "10.0.0.0/16",
                    "ExportName": "NetworkStack-VpcCidr"
                },
                {
                    "OutputKey": "Vpc",
                    "OutputValue": "vpc-06fed38823bb2c6d8",
                    "ExportName": "NetworkStack-Vpc"
                },
                {
                    "OutputKey": "PrivateSubnetAZ1Cidr",
                    "OutputValue": "10.0.2.0/24",
                    "ExportName": "NetworkStack-PrivateSubnetAZ1Cidr"
                },
                {
                    "OutputKey": "PrivateSubnetAZ2",
                    "OutputValue": "subnet-0f75156fd2c2bba26",
                    "ExportName": "NetworkStack-PrivateSubnetAZ2"
                },
                {
                    "OutputKey": "PrivateSubnetAZ1",
                    "OutputValue": "subnet-018273f9dd6a65b2b",
                    "ExportName": "NetworkStack-PrivateSubnetAZ1"
                },
                {
                    "OutputKey": "PublicSubnetAZ1Cidr",
                    "OutputValue": "10.0.0.0/24",
                    "ExportName": "NetworkStack-PublicSubnetAZ1Cidr"
                }
            ],
            "Tags": [],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}

出力の詳細についてAWS CLIのドキュメントをご参照下さい。

describe-stacks - AWS CLI 2.0.61 Command Reference

あとはこの取得したjsonから欲しい値を取得していきます。

取得したjsonからアウトプットパラメータを取得する

jsonから値を取得するために、今回は jq を使用します。

インストールしていない方は以下のコマンドを実行してください。

sudo yum -y install jq

まずはjsonの中のOutputsを取得していきましょう。先ほどのコマンドで取得したjsonからjqを使って整形します。

$ aws cloudformation describe-stacks --stack-name NetworkStack  | jq -r '.Stacks[] | .Outputs[]'              
{
  "OutputKey": "PublicSubnetAZ1",
  "OutputValue": "subnet-0d83a103c6102239e",
  "ExportName": "NetworkStack-PublicSubnetAZ1"
}
{
  "OutputKey": "PublicSubnetAZ2Cidr",
  "OutputValue": "10.0.1.0/24",
  "ExportName": "NetworkStack-PublicSubnetAZ2Cidr"
}
{
  "OutputKey": "PublicSubnetAZ2",
  "OutputValue": "subnet-03da5606647c8e00d",
  "ExportName": "NetworkStack-PublicSubnetAZ2"
}
{
  "OutputKey": "PrivateSubnetAZ2Cidr",
  "OutputValue": "10.0.3.0/24",
  "ExportName": "NetworkStack-PrivateSubnetAZ2Cidr"
}
{
  "OutputKey": "VpcCidr",
  "OutputValue": "10.0.0.0/16",
  "ExportName": "NetworkStack-VpcCidr"
}
{
  "OutputKey": "Vpc",
  "OutputValue": "vpc-06fed38823bb2c6d8",
  "ExportName": "NetworkStack-Vpc"
}
{
  "OutputKey": "PrivateSubnetAZ1Cidr",
  "OutputValue": "10.0.2.0/24",
  "ExportName": "NetworkStack-PrivateSubnetAZ1Cidr"
}
{
  "OutputKey": "PrivateSubnetAZ2",
  "OutputValue": "subnet-0f75156fd2c2bba26",
  "ExportName": "NetworkStack-PrivateSubnetAZ2"
}
{
  "OutputKey": "PrivateSubnetAZ1",
  "OutputValue": "subnet-018273f9dd6a65b2b",
  "ExportName": "NetworkStack-PrivateSubnetAZ1"
}
{
  "OutputKey": "PublicSubnetAZ1Cidr",
  "OutputValue": "10.0.0.0/24",
  "ExportName": "NetworkStack-PublicSubnetAZ1Cidr"
}

いい感じにOutputsの中を取得できましたね。あとはこの中からkeyを指定して欲しい値を取得していきます。

VPCのIDを取得する

先ほどはアウトプットしたパラメータを全て取得していましたが、次にVPCのIDを取得していきます。

先ほどのjsonで言えばVPCは以下のあたりですね。欲しい値はvpc-06fed38823bb2c6d8です。

{
  "OutputKey": "Vpc",
  "OutputValue": "vpc-06fed38823bb2c6d8",
  "ExportName": "NetworkStack-Vpc"
}

まずはこの情報を取得していきたいので、OutputKeyVpcのものを jq の select で取得していきます。

$ aws cloudformation describe-stacks --stack-name NetworkStack | jq -r '.Stacks[] | .Outputs[] | select(.OutputKey == "Vpc")'
{
  "OutputKey": "Vpc",
  "OutputValue": "vpc-06fed38823bb2c6d8",
  "ExportName": "NetworkStack-Vpc"
}

想定通りに取得することができました。今回はOutputValueの値が欲しいので、ここからさらに絞りこみます。

$ aws cloudformation describe-stacks --stack-name NetworkStack | jq -r '.Stacks[] | .Outputs[] | select(.OutputKey == "Vpc") | .OutputValue ' 
vpc-06fed38823bb2c6d8

これでようやく欲しかったVPCのIDを取得することができました。あとはこの値をシェルの中で変数に入れるなりして自由に使うことができます。

他のアウトプットリソースを取得したい場合は、select(.OutputKey == "Vpc")で指定しているVpcを他の値に変更してあげましょう。

  • Public Subnet 1のSubnet IDが欲しい場合
$ aws cloudformation describe-stacks --stack-name NetworkStack | jq -r '.Stacks[] | .Outputs[] | select(.OutputKey == "PublicSubnetAZ1") | .OutputValue '
subnet-0d83a103c6102239e
  • Private Subnet 1のCIDRが欲しい場合
$ aws cloudformation describe-stacks --stack-name NetworkStack | jq -r '.Stacks[] | .Outputs[] | select(.OutputKey == "PrivateSubnetAZ1Cidr") | .OutputValue ' 
10.0.2.0/24

これで欲しい値をいい感じに取得することができるようになりました。

まとめ

AWS CLIで事前に作成したスタックのアウトプットパラメータを取得してみました。CloudFormationに対応していないリソース作成のとき、たまに使うことがありそうなので是非覚えておきましょう!