こんにちは。たかやまです。
普段CDKを使ってリソース構築を行っていますが最終的な運用としてCloudFormationテンプレートを利用したいときがあります。
CloudFormationテンプレートで運用する場合、テンプレートへ自由に値を渡せるParametersを利用すると思います。このParametersはCDKでもCfnParameter*1としてサポートされていて定義することができます。
1通常のCDK利用の場合は、CDKアプリ内でのパラメータ定義が推奨されます。
ただ、こちらのParametersですがデフォルト状態だとパラメータ名で昇順に並べ替えされてしまいます。
こちらを任意の順番に並び変える場合、CloudFormationではAWS::CloudFormation::Interfaceを利用することで並び順を変更することができます。ただ、こちらのAWS::CloudFormation::Interface
はCDKのL1でサポートされていません。
ただ、Issue内でも上げられているtemplateOptions.metadataを利用することで、CDKでもAWS::CloudFormation::Interfaceを設定できるので今回こちらを試していきたいと思います。
やってみた
AWS::CloudFormation::Interfaceの設定
templateOptions.metadata
を利用して、AWS::CloudFormation::Interfaceを設定していきたいと思います。
ここではAWS::CloudFormation::Interface
のドキュメントで書かれているサンプルをCDKで設定してみたいと思います。
AWS::CloudFormation::Interface - AWS CloudFormation
こちらのParametersとInterfaceをCDKで設定すると以下のようになります。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkInterfaceStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Parameters
const vpcId = new cdk.CfnParameter(this, 'VpcId', {
type: 'AWS::EC2::VPC::Id',
description: 'VpcId of you existing VPC',
});
const subnetId = new cdk.CfnParameter(this, 'SubnetId', {
type: 'AWS::EC2::Subnet::Id',
description: 'The list of SubnetIds for the VPC',
});
const securityGroupId = new cdk.CfnParameter(this, 'SecurityGroupId', {
type: 'AWS::EC2::SecurityGroup::Id',
description: 'The list of SecurityGroupIds for the VPC',
});
const instanceType = new cdk.CfnParameter(this, 'InstanceType', {
type: 'String',
description: 'EC2 instance type to use for the instance',
default: 't3.micro',
});
const keyPairName = new cdk.CfnParameter(this, 'KeyPairName', {
type: 'AWS::EC2::KeyPair::KeyName',
description: 'Name of an existing EC2 KeyPair to enable SSH access to the instance',
});
// Interface
this.templateOptions.metadata = {
'AWS::CloudFormation::Interface': {
ParameterGroups: [
{
Label: { default: 'Network Configuration' },
Parameters: [vpcId.logicalId, subnetId.logicalId, securityGroupId.logicalId],
},
{
Label: { default: 'Amazon EC2 Configuration' },
Parameters: [instanceType.logicalId, keyPairName.logicalId],
},
],
ParameterLabels: {
VpcId: { default: 'Which VPC should this be deployed to?' },
},
},
};
}
}
見ていただくとわかる通り、templateOptions.metadata
にCloudFormationで定義するJson形式の構文と同様の内容を渡してあげることで定義することができます。
やりたいことは上記のコードで実現できたのですが、せっかくCDKを利用しているのでメソッドを利用してInterfaceを定義していきたいと思います。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkInterfaceStack extends cdk.Stack {
private paramGroups: any[] = [];
private paramLabels: any = {};
private addToParamGroups(label: string, ...param: string[]) {
this.paramGroups.push({
Label: { default: label },
Parameters: param,
});
}
private addToParamLabels(label: string, param: string) {
this.paramLabels[param] = {
default: label,
};
}
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Parameters
const vpcId = new cdk.CfnParameter(this, 'VpcId', {
type: 'AWS::EC2::VPC::Id',
description: 'VpcId of you existing VPC',
});
const subnetId = new cdk.CfnParameter(this, 'SubnetId', {
type: 'AWS::EC2::Subnet::Id',
description: 'The list of SubnetIds for the VPC',
});
const securityGroupId = new cdk.CfnParameter(this, 'SecurityGroupId', {
type: 'AWS::EC2::SecurityGroup::Id',
description: 'The list of SecurityGroupIds for the VPC',
});
const instanceType = new cdk.CfnParameter(this, 'InstanceType', {
type: 'String',
description: 'EC2 instance type to use for the instance',
default: 't3.micro',
});
const keyPairName = new cdk.CfnParameter(this, 'KeyPairName', {
type: 'AWS::EC2::KeyPair::KeyName',
description: 'Name of an existing EC2 KeyPair to enable SSH access to the instance',
});
// Interface
this.addToParamGroups('Network Configuration', vpcId.logicalId, subnetId.logicalId, securityGroupId.logicalId);
this.addToParamGroups('Amazon EC2 Configuration', instanceType.logicalId, keyPairName.logicalId);
this.addToParamLabels('Which VPC should this be deployed to?', vpcId.logicalId);
this.templateOptions.metadata = {
'AWS::CloudFormation::Interface': {
ParameterGroups: this.paramGroups,
ParameterLabels: this.paramLabels,
},
};
}
}
Jsonを扱わなくてよくなり多少見栄えがよくなりました。
CloudFormationテンプレートの生成
では定義したCDKからCloudFormationテンプレートを生成(cdk synth
)してみます。
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Network Configuration
Parameters:
- VpcId
- SubnetId
- SecurityGroupId
- Label:
default: Amazon EC2 Configuration
Parameters:
- InstanceType
- KeyPairName
ParameterLabels:
VpcId:
default: Which VPC should this be deployed to?
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VpcId of you existing VPC
SubnetId:
Type: AWS::EC2::Subnet::Id
Description: The list of SubnetIds for the VPC
SecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
Description: The list of SecurityGroupIds for the VPC
InstanceType:
Type: String
Default: t3.micro
Description: EC2 instance type to use for the instance
KeyPairName:
Type: AWS::EC2::KeyPair::KeyName
Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/hnb659fds/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Resources:
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/yWMMQ6AIBDA3uIOJzq58wGDL0A4kxM5EkAdjH9X49R2aQ9DB6qxZ5HOB7nRDNdUrQtCLzzabCNWzF8YLGnPDj/XiT1VSnwLTh5hLe3RDaDe01qIZN65UkQwPx/hXa3cZQAAAA==
Metadata:
aws:cdk:path: CdkInterfaceStack/CDKMetadata/Default
Condition: CDKMetadataAvailable
Conditions:
CDKMetadataAvailable:
Fn::Or:
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- af-south-1
- Fn::Equals:
- Ref: AWS::Region
- ap-east-1
- Fn::Equals:
- Ref: AWS::Region
- ap-northeast-1
- Fn::Equals:
- Ref: AWS::Region
- ap-northeast-2
- Fn::Equals:
- Ref: AWS::Region
- ap-south-1
- Fn::Equals:
- Ref: AWS::Region
- ap-southeast-1
- Fn::Equals:
- Ref: AWS::Region
- ap-southeast-2
- Fn::Equals:
- Ref: AWS::Region
- ca-central-1
- Fn::Equals:
- Ref: AWS::Region
- cn-north-1
- Fn::Equals:
- Ref: AWS::Region
- cn-northwest-1
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- eu-central-1
- Fn::Equals:
- Ref: AWS::Region
- eu-north-1
- Fn::Equals:
- Ref: AWS::Region
- eu-south-1
- Fn::Equals:
- Ref: AWS::Region
- eu-west-1
- Fn::Equals:
- Ref: AWS::Region
- eu-west-2
- Fn::Equals:
- Ref: AWS::Region
- eu-west-3
- Fn::Equals:
- Ref: AWS::Region
- me-south-1
- Fn::Equals:
- Ref: AWS::Region
- sa-east-1
- Fn::Equals:
- Ref: AWS::Region
- us-east-1
- Fn::Equals:
- Ref: AWS::Region
- us-east-2
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- us-west-1
- Fn::Equals:
- Ref: AWS::Region
- us-west-2
Rules:
CheckBootstrapVersion:
Assertions:
- Assert:
Fn::Not:
- Fn::Contains:
- - "1"
- "2"
- "3"
- "4"
- "5"
- Ref: BootstrapVersion
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
生成されたCloudFormationテンプレートを見ていただくと分かる通り、CloudFormationテンプレートとして利用する分にはMetadataやBootstrapなどの不要な情報が入ってしまっています。
こちらの情報は以下のオプションを設定することで削除することができます。
- CDKアプリで
generateBootstarapVersionRule
をfalseに設定する cdk synth
の際に--no-version-reporting
と--no-path-metadata
を設定する
実際の例で見ると以下のようになります。
bin/cdk.ts
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import 'source-map-support/register';
import { CdkInterfaceStack } from '../lib/cdk-interface-stack';
const app = new cdk.App();
new CdkInterfaceStack(app, 'CdkInterfaceStack', {
synthesizer: new cdk.DefaultStackSynthesizer({ generateBootstrapVersionRule: false }),
});
bin配下のCDKアプリにgenerateBootstarapVersionRule
にfalseに設定したあと、
cdk synth --no-version-reporting --no-path-metadata
を実行すると以下のようなテンプレートが生成されます。
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Network Configuration
Parameters:
- VpcId
- SubnetId
- SecurityGroupId
- Label:
default: Amazon EC2 Configuration
Parameters:
- InstanceType
- KeyPairName
ParameterLabels:
VpcId:
default: Which VPC should this be deployed to?
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VpcId of you existing VPC
SubnetId:
Type: AWS::EC2::Subnet::Id
Description: The list of SubnetIds for the VPC
SecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
Description: The list of SecurityGroupIds for the VPC
InstanceType:
Type: String
Default: t3.micro
Description: EC2 instance type to use for the instance
KeyPairName:
Type: AWS::EC2::KeyPair::KeyName
Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
CDKのMetadataやBootstrapの情報が削除されスッキリしましたね。あとは、普段通りCDKでリソースを定義していけばOKです!
最後に
今回の手法を利用することで、CloudFormationで運用する必要がある環境のテンプレートの作成でもCDKを活用することができます。
CDKを利用することでコーディング工数を削減できるので、CloudFormationの作成でもCDKを活用していきたいですね!
小ネタでしたが、こちらの記事がどなたかの助けになれば幸いです。
以上、たかやま(@nyan_kotaroo)でした。