こんにちは、CX 事業本部製造ビジネステクノロジー部の若槻です。
AWS CDKでは、単体または複数のファイルを アセット として S3 バケットにアップロードすることができる aws_s3_assets というモジュールが提供されています。
今回は、この aws_s3_assets モジュールを使ってアップロードしたアセットを、Amazon EC2のインスタンスにダウンロード可能にしてみました。
やってみた
アセット
アップロードしたいアセットのファイルを用意します。一方のスクリプトがもう一方のファイルを参照するようにしています。
asset/sample-server/DATA
Hello, World!
asset/sample-server/script.sh
cat DATA
CDK コード
AWS CDK でインスタンスおよびアセットを定義する実装コード(TypeScript)です。
lib/cdk-sample-stack.ts
import { aws_ec2, aws_s3_assets, aws_ssm, Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as path from 'path';
export class CdkSampleStack extends Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
const vpcCidr = '10.100.0.0/16';
const ec2InstanceConnectSourceIpRange = '3.112.23.0/29';
// VPC を作成
const vpc = new aws_ec2.Vpc(this, 'Vpc', {
ipAddresses: aws_ec2.IpAddresses.cidr(vpcCidr),
subnetConfiguration: [
{
cidrMask: 24,
name: 'public',
subnetType: aws_ec2.SubnetType.PUBLIC,
},
],
maxAzs: 1,
});
// セキュリティグループを作成
const securityGroup = new aws_ec2.SecurityGroup(this, 'SecurityGroup', {
vpc,
});
// セキュリティグループに EC2 Instance Connect 用のインバウンドルールを追加
securityGroup.addIngressRule(
aws_ec2.Peer.ipv4(ec2InstanceConnectSourceIpRange),
aws_ec2.Port.tcp(22),
'SSH by EC2 Instance Connect in ap-northeast-1'
);
// EC2 インスタンスを作成
const instance = new aws_ec2.Instance(this, 'Instance', {
vpc,
securityGroup,
instanceType: aws_ec2.InstanceType.of(
aws_ec2.InstanceClass.T2,
aws_ec2.InstanceSize.MICRO
),
machineImage: aws_ec2.MachineImage.latestAmazonLinux2023(),
requireImdsv2: true,
});
// S3 バケットにアセットをアップロード
const sampleServerAsset = new aws_s3_assets.Asset(
this,
'SampleServerAsset',
{
path: path.join(__dirname, '../asset/sample-server'),
}
);
// SSM パラメータストアにアセットの S3 URI を保存
const sampleServerAssetS3UriParameter = new aws_ssm.StringParameter(
this,
'SampleServerAssetS3UriParameter',
{
parameterName: `/sample-server/asset/s3-uri`,
stringValue: sampleServerAsset.s3ObjectUrl,
}
);
// アセットおよびアセットの S3 URI を保存したパラメーターへの読み取り権限をインスタンスに付与
sampleServerAsset.grantRead(instance);
sampleServerAssetS3UriParameter.grantRead(instance);
}
}
aws_s3_assets.Asset
コンストラクトクラスで、指定したディレクトリのアセットを S3 バケットにアップロードします。aws_ssm.StringParameter
コンストラクトクラスで、アセットの S3 URI を SSM パラメータストアに保存します。これによりアセットを利用する際の S3 URI を取得できるようにします。grantRead
メソッドで、インスタンスにアセットおよびアセットの S3 URI を読み取る権限を付与します。
上記実装の CDK アプリケーションをデプロイします。
インスタンスにアセットをダウンロードする
EC2 Instance Connect を使用して、インスタンスにログインします。
アセットが配置されている S3 バケットの URI をパラメーターストアから取得します。
asset_s3_uri=$(aws ssm get-parameter --name "/sample-server/asset/s3-uri" --query "Parameter.Value" --output text --region ap-northeast-1)
S3 バケットからアセットをダウンロードし、展開します。
sudo aws s3 cp $asset_s3_uri ./asset.zip
sudo unzip ./asset.zip
sudo rm ./asset.zip
アセットとして取得したスクリプトを実行することができました。
$ sudo ./script.sh
Hello, World!
アセットの実体の配置場所
CDK により作成された CloudFormation スタックを確認すると、アセットに該当するコンストラクトが作成されていませんでした。アセットの実体はどこに配置されているのでしょうか。
結論としては、CDK のブートストラップ時に作成される S3 バケットになります。
$ aws ssm get-parameter --name "/sample-server/asset/s3-uri" --query "Parameter.Value" --output text --region ap-northeast-1
s3://cdk-hnb659fds-assets-XXXXXXXXXXXX-ap-northeast-1/bab74bb1ba49c19ce901c62b25cfe5f7132c7bbad71228ab6def3d89d1695d10.zip
インスタンスプロファイルの IAM ロールにも、アセットを読み取る権限が付与されていることが確認できます。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetBucket*",
"s3:GetObject*",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::cdk-hnb659fds-assets-XXXXXXXXXXXX-ap-northeast-1/*",
"arn:aws:s3:::cdk-hnb659fds-assets-XXXXXXXXXXXX-ap-northeast-1"
],
"Effect": "Allow"
},
{
"Action": [
"ssm:DescribeParameters",
"ssm:GetParameter",
"ssm:GetParameterHistory",
"ssm:GetParameters"
],
"Resource": "arn:aws:ssm:ap-northeast-1:XXXXXXXXXXXX:parameter/sample-server/asset/s3-uri",
"Effect": "Allow"
}
]
}
おわりに
AWS CDK の aws_s3_assets モジュールを使ってアップロードしたアセットを、EC2 インスタンスにダウンロード可能にしてみました。
今回のような EC2 インスタンスでの利用に限らず、汎用的なアセットの管理方法として活用できるモジュールです。ぜひご活用ください。
以上