[AWS CDK] AWS Config が有効化済みであるにも関わらずコントロール Config.1 が失敗する場合はサービスリンクロールを確認しよう
こんにちは、製造ビジネステクノロジー部の若槻です。
今回は、AWS CDK で AWS Config を有効化したにも関わらずコントロール Config.1
が失敗する場合はサービスリンクロールを確認しよう、という共有です。
事象
次のような CDK コードで AWS Config の有効化設定を行いました。
// Config.1 コントロールが失敗する実装
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as config from 'aws-cdk-lib/aws-config';
export class AwsConfigConstruct extends Construct {
public readonly bucket: s3.Bucket;
constructor(scope: Construct, id: string) {
super(scope, id);
const accountId = cdk.Stack.of(this).account;
// AWS Config ログ保存用の S3 バケットを作成
const logDestinationBucket = new s3.Bucket(this, 'LogDestinationBucket');
logDestinationBucket.addToResourcePolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:PutObject'],
resources: [logDestinationBucket.arnForObjects('*')],
principals: [new iam.ServicePrincipal('config.amazonaws.com')],
})
);
logDestinationBucket.addToResourcePolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:GetBucketAcl', 's3:ListBucket'],
resources: [logDestinationBucket.bucketArn],
principals: [new iam.ServicePrincipal('config.amazonaws.com')],
})
);
// サービスロールを作成
const role = new iam.Role(this, 'Role', {
assumedBy: new iam.ServicePrincipal('config.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
'service-role/AWS_ConfigRole'
),
],
});
// AWS Config の設定
const recorder = new config.CfnConfigurationRecorder(
this,
'Recorder',
{
roleArn: role.roleArn,
recordingGroup: {
allSupported: true,
includeGlobalResourceTypes: true,
},
}
);
recorder.node.addDependency(role);
// AWS Config のデリバリーチャネル
const deliveryChannel = new config.CfnDeliveryChannel(
this,
'DeliveryChannel',
{
s3BucketName: logDestinationBucket.bucketName,
s3KeyPrefix: 'aws-config',
configSnapshotDeliveryProperties: {
deliveryFrequency: 'TwentyFour_Hours',
},
}
);
deliveryChannel.node.addDependency(logDestinationBucket);
}
}
上記デプロイ後にしばらくすると Security Hub で下記のコントロールのアラートが発生しました。
[Config.1] AWS Config should be enabled and use the service-linked role for resource recording
DevelopersIO の記事だとこちらで紹介されているものです。
原因、解決
AWS Config のレコーダーを作成する際には、AWS Config が AWS リソースの詳細設定を取得したり、S3 バケットへログを書き込んだりする権限を持つ IAM ロールを割り当てる必要があります。
この割り当てる IAM ロールをサービスリンクロールとしてないことが原因でした。
元の実装では AWS_ConfigRole
というマネージドポリシーをアタッチしたロールを作成して AWS Config のレコーダーに割り当てていました。
マネージドポリシー AWS_ConfigRole
の実体はこちら。
説明を読む限り、このポリシーを付与するのでも問題は無さそう。実際 AWS Config によるリソースの変更追跡はできていました。
Default policy for AWS Config service role. Provides permissions required for AWS Config to track changes to your AWS resources.
(日本語訳)
AWS Config サービスロールのデフォルトポリシー。AWS リソースへの変更を追跡するために AWS Config に必要なアクセス許可を提供します。
しかし、ドキュメントをさらに確認すると、推奨されているのはサービスリンクロール(Service-Linked Role)の使用だとのことです。
そこで下記のように config.amazonaws.com
サービスを信頼するサービスリンクロールを作成し、AWS Config のレコーダーに割り当てるように修正します。
// Config.1 コントロールが失敗しない実装
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as config from 'aws-cdk-lib/aws-config';
export class AwsConfigConstruct extends Construct {
public readonly bucket: s3.Bucket;
constructor(scope: Construct, id: string) {
super(scope, id);
const accountId = cdk.Stack.of(this).account;
// AWS Config ログ保存用の S3 バケットを作成
const logDestinationBucket = new s3.Bucket(this, 'LogDestinationBucket');
logDestinationBucket.addToResourcePolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:PutObject'],
resources: [logDestinationBucket.arnForObjects('*')],
principals: [new iam.ServicePrincipal('config.amazonaws.com')],
})
);
logDestinationBucket.addToResourcePolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:GetBucketAcl', 's3:ListBucket'],
resources: [logDestinationBucket.bucketArn],
principals: [new iam.ServicePrincipal('config.amazonaws.com')],
})
);
// サービスリンクロールを作成
const role = new iam.CfnServiceLinkedRole(this, 'ConfigServiceLinkedRole', {
awsServiceName: 'config.amazonaws.com',
});
// AWS Config の設定
const recorder = new config.CfnConfigurationRecorder(this, 'Recorder', {
roleArn: `arn:aws:iam::${accountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig`,
recordingGroup: {
allSupported: true,
includeGlobalResourceTypes: true,
},
});
recorder.node.addDependency(role);
// AWS Config のデリバリーチャネル
const deliveryChannel = new config.CfnDeliveryChannel(
this,
'DeliveryChannel',
{
s3BucketName: logDestinationBucket.bucketName,
s3KeyPrefix: 'aws-config',
configSnapshotDeliveryProperties: {
deliveryFrequency: 'TwentyFour_Hours',
},
}
);
deliveryChannel.node.addDependency(logDestinationBucket);
}
}
ポイントは下記の実装によりサービスリンクロールをあらかじめ作成している点です。
new iam.CfnServiceLinkedRole(this, 'ConfigServiceLinkedRole', {
awsServiceName: 'config.amazonaws.com',
});
これにより下記のように AWSServiceRoleForConfig
というサービスロールが作成されるので、これを AWS Config のレコーダーに割り当てます。
念の為、差分は以下の通りです。
diff --git a/lib/constructs/aws-config/index.ts b/lib/constructs/aws-config/index.ts
index f8242d3..1528b69 100644
--- a/lib/constructs/aws-config/index.ts
+++ b/lib/constructs/aws-config/index.ts
@@ -30,14 +30,9 @@ export class AwsConfigConstruct extends Construct {
})
);
- // サービスロールを作成
- const role = new iam.Role(this, 'Role', {
- assumedBy: new iam.ServicePrincipal('config.amazonaws.com'),
- managedPolicies: [
- iam.ManagedPolicy.fromAwsManagedPolicyName(
- 'service-role/AWS_ConfigRole'
- ),
- ],
+ // サービスリンクロールを作成
+ const role = new iam.CfnServiceLinkedRole(this, 'ConfigServiceLinkedRole', {
+ awsServiceName: 'config.amazonaws.com',
});
// AWS Config の設定
@@ -45,7 +40,7 @@ export class AwsConfigConstruct extends Construct {
this,
'Recorder',
{
- roleArn: role.roleArn,
+ roleArn: `arn:aws:iam::${accountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig`,
recordingGroup: {
allSupported: true,
includeGlobalResourceTypes: true,
上記対応により、Security Hub のアラートを解消することができました。
おわりに
AWS CDK で AWS Config を有効化したにも関わらずコントロール Config.1
が失敗する場合はサービスリンクロールを確認しよう、という共有でした。
以上