-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
logs: Support Resource policies #5343
Comments
maybe |
Correct, but as far as I know CloudWatch Log Groups don't have resource policies? |
So what seems to be the case is that CloudWatch supports account-wide log policies, but CloudFormation doesn't support creating them. These log policies seem to apply to all log groups at the same time though, not individual ones. Marking this as a "needs cfn" feature request. |
Correct, I was trying to create a policy for ES to attach a log group to ES domain. https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-createupdatedomains.html https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutResourcePolicy.html |
Your workaround for any feature that is not supported by CFN will be "custom resource". |
Yeah I created 2 custom resources yesterday. This is lower priority for me. |
Also, I noticed that CDK uses a custom resource to set log retention on lambda log groups. Is that a related piece to cfn not supporting it? Should I open an issue to the CloudFormation team somewhere? |
I believe CFN does not support this. An issue to CFN team would always be appreciate to try and get movement on things. |
Sure thing @rix0rrr. I have been creating some other GitHub issues on the Cloudformation roadmap. |
Created at aws-cloudformation/cloudformation-coverage-roadmap#359 Feel free to suggest updates to my description. |
hey @cmckni3 are there any good examples out there for how to make a custom resource like you describe? i'm still learning CF and such. |
@paul42 the CDK repo has custom resource examples |
In case others run into this, I used the Here's some code to hopefully help out if folks need to use this workaround in the meantime. Please note that this code is very specific to our use-case, so you'll almost undoubtedly need to modify it to work for you. // Cloudwatch logs have global resource policies that allow EventBridge to
// write logs to a given Cloudwatch Log group. That's currently not exposed
// via CloudFormation, so we use a Custom Resource here.
// See https://github.com/aws/aws-cdk/issues/5343
const policyName = '<fill in your unique policy name>'
new cr.AwsCustomResource(this, "CloudwatchLogResourcePolicy", {
resourceType: "Custom::CloudwatchLogResourcePolicy",
onUpdate: {
service: "CloudWatchLogs",
action: "putResourcePolicy",
parameters: {
policyName,
// PolicyDocument must be provided as a string, so we can't use the iam.PolicyDocument provisions
// or other CDK niceties here.
policyDocument: JSON.stringify({
Version: "2012-10-17",
Statement: [
{
Sid: policyName,
Effect: "Allow",
Principal: {
Service: ["delivery.logs.amazonaws.com", "events.amazonaws.com"],
},
Action: ["logs:CreateLogStream", "logs:PutLogEvents"],
// I'd prefer to use cdk.Arn.format() here, but that creates Fn::Join's in the template,
// which AwsCustomResource can't handle.
Resource: '<fill in your arn here>',
},
],
}),
},
physicalResourceId: cr.PhysicalResourceId.of(policyName),
},
onDelete: {
service: "CloudWatchLogs",
action: "deleteResourcePolicy",
parameters: {
policyName,
},
},
policy: cr.AwsCustomResourcePolicy.fromStatements([
new iam.PolicyStatement({
actions: ["logs:PutResourcePolicy", "logs:DeleteResourcePolicy"],
// Resource Policies are global in Cloudwatch Logs per-region, per-account.
resources: ["*"],
}),
]),
}); |
@blimmer same here. Have been using AwsCustomResource heavily for other API calls. Switched logs and resource policies over to AwsCustomResource 2 weeks ago. |
I'm also trying to create a log group to ES domain. Here is my code combining @blimmer 's custom resource example. import cdk = require('@aws-cdk/core');
import {CfnDomain} from '@aws-cdk/aws-elasticsearch';
import {LogGroup, RetentionDays} from '@aws-cdk/aws-logs';
import {PolicyStatement} from '@aws-cdk/aws-iam';
import {AwsCustomResource, PhysicalResourceId, AwsCustomResourcePolicy} from '@aws-cdk/custom-resources'
const region = "us-west-2";
export class MonitorDevStack extends cdk.Stack {
constructor(scope: cdk.App) {
super(scope, 'MonitorDevStack', {
env : {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: region || process.env.CDK_DEFAULT_REGION
}
});
const domainName = this.stackName.toLowerCase();
const ES_APPLICATION_LOGS = new LogGroup(this, 'ES_APPLICATION_LOGS', {
logGroupName: `/aws/aes/domains/${domainName}/application-logs/`,
retention: RetentionDays.THREE_MONTHS
});
// Cloudwatch logs have global resource policies that allow EventBridge to
// write logs to a given Cloudwatch Log group. That's currently not exposed
// via CloudFormation, so we use a Custom Resource here.
// See https://github.com/aws/aws-cdk/issues/5343
const policyName = `${this.stackName}-ElastichsearchToCloudWatchPolicy`;
const policy = new AwsCustomResource(this, "CloudwatchLogResourcePolicy", {
resourceType: "Custom::CloudwatchLogResourcePolicy",
onUpdate: {
service: "CloudWatchLogs",
action: "putResourcePolicy",
parameters: {
policyName,
// PolicyDocument must be provided as a string, so we can't use the iam.PolicyDocument provisions
// or other CDK niceties here.
policyDocument: JSON.stringify({
Version: "2012-10-17",
Statement: [
{
Sid: policyName,
Effect: "Allow",
Principal: {
Service: ["es.amazonaws.com"],
},
Action: ["logs:CreateLogStream", "logs:PutLogEvents", "logs:PutLogEventsBatch"],
// I'd prefer to use cdk.Arn.format() here, but that creates Fn::Join's in the template,
// which AwsCustomResource can't handle.
Resource: ES_APPLICATION_LOGS.logGroupArn,
},
],
}),
},
physicalResourceId: PhysicalResourceId.of(policyName),
},
onDelete: {
service: "CloudWatchLogs",
action: "deleteResourcePolicy",
parameters: {
policyName,
},
},
policy: AwsCustomResourcePolicy.fromStatements([
new PolicyStatement({
actions: ["logs:PutResourcePolicy", "logs:DeleteResourcePolicy"],
// Resource Policies are global in Cloudwatch Logs per-region, per-account.
resources: ["*"],
}),
]),
});
const elasticsearchDomain = new CfnDomain(
this,
'ElasticsearchDomain',
{
accessPolicies: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Principal: {
AWS: '*',
},
Action: [
"es:ESHttp*"
],
Resource: `arn:aws:es:${this.region}:${this.account}:domain/${domainName}/*`,
},
],
},
ebsOptions: {
ebsEnabled: true,
volumeSize: 20,
volumeType: 'standard',
},
elasticsearchClusterConfig: {
instanceCount: 2,
instanceType: 't2.medium.elasticsearch',
zoneAwarenessConfig: {
availabilityZoneCount: 2
},
zoneAwarenessEnabled: true
},
domainName: domainName,
encryptionAtRestOptions: {
enabled: false,
},
nodeToNodeEncryptionOptions: {
enabled: true,
},
vpcOptions: {
securityGroupIds: ["sg-xxxxxxx"],
subnetIds: ["subnet-aaaaaa", "subnet-bbbbb"],
},
elasticsearchVersion: '7.4',
logPublishingOptions: {
"ES_APPLICATION_LOGS": {
cloudWatchLogsLogGroupArn: ES_APPLICATION_LOGS.logGroupArn,
enabled: true
}
}
}
);
new cdk.CfnOutput(this, `ElasticEndpoint`, { value: elasticsearchDomain.attrDomainEndpoint });
}
} |
@JoHuang I have the same problem than you, did you manage to make it work? EDIT "ES_APPLICATION_LOGS": {
cloudWatchLogsLogGroupArn: ES_APPLICATION_LOGS.logGroupArn,
enabled: false
} and after the first run you set "ES_APPLICATION_LOGS": {
cloudWatchLogsLogGroupArn: ES_APPLICATION_LOGS.logGroupArn,
enabled: true
} it will work |
CloudFormation now supports Cloudwatch Resource policies: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-resourcepolicy.html |
CloudFormation now supports [Cloudwatch logs Resource policies](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-resourcepolicy.html) This PR adds L2 support for it. And now its possible to grant access to service principals as follows. Previously this was throwing an error - see #5343 ```ts const eventsTargetLogs = new logs.LogGroup(this, 'EventsTargetLogGroup'); eventsTargetLogs.grantWrite(new iam.ServicePrincipal('events.amazonaws.com')).assertSuccess(); ``` In future, following custom resource implementation of `LogGroupResourcePolicy` could be replaced. https://github.com/aws/aws-cdk/blob/83b8df8c390a27e10bf362f49babfb24ee425506/packages/@aws-cdk/aws-elasticsearch/lib/log-group-resource-policy.ts#L25 https://github.com/aws/aws-cdk/blob/a872e672f8990fc3879413e5d797533d3916e1fd/packages/@aws-cdk/aws-events-targets/lib/log-group-resource-policy.ts#L26 https://github.com/aws/aws-cdk/blob/a872e672f8990fc3879413e5d797533d3916e1fd/packages/@aws-cdk/aws-events-targets/lib/log-group-resource-policy.ts#L26 closes #5343 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
|
CloudFormation now supports [Cloudwatch logs Resource policies](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-resourcepolicy.html) This PR adds L2 support for it. And now its possible to grant access to service principals as follows. Previously this was throwing an error - see aws#5343 ```ts const eventsTargetLogs = new logs.LogGroup(this, 'EventsTargetLogGroup'); eventsTargetLogs.grantWrite(new iam.ServicePrincipal('events.amazonaws.com')).assertSuccess(); ``` In future, following custom resource implementation of `LogGroupResourcePolicy` could be replaced. https://github.com/aws/aws-cdk/blob/83b8df8c390a27e10bf362f49babfb24ee425506/packages/@aws-cdk/aws-elasticsearch/lib/log-group-resource-policy.ts#L25 https://github.com/aws/aws-cdk/blob/a872e672f8990fc3879413e5d797533d3916e1fd/packages/@aws-cdk/aws-events-targets/lib/log-group-resource-policy.ts#L26 https://github.com/aws/aws-cdk/blob/a872e672f8990fc3879413e5d797533d3916e1fd/packages/@aws-cdk/aws-events-targets/lib/log-group-resource-policy.ts#L26 closes aws#5343 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
It looks like AWS GovCloud Regions do not yet have support for
|
@michaelfedell |
@nom3ad - thanks for the suggestion! I have written an aspect to do this, but I have not been able to find any references on pruning a node from the resource tree. Could you provide some guidance here? @jsii.implements(cdk.IAspect)
class RemoveLogsPolicyAspect:
def visit(self, node: IConstruct) -> None:
if isinstance(node, logs.CfnResourcePolicy):
msg = "AWS::Logs::ResourcePolicy is not yet supported in GovCloud; removing from template."
cdk.Annotations.of(node).add_warning(msg)
# TODO: Remove node from stack |
Ended up solving this with: @jsii.implements(cdk.IAspect)
class RemoveLogsPolicyAspect:
def visit(self, node: IConstruct) -> None:
if isinstance(node, logs.ResourcePolicy):
stack = cdk.Stack.of(node)
# This Node is an L2 Construct for aws-cdk.aws-logs.ResourcePolicy
# The default_child is of type AWS::Logs::ResourcePolicy, we can remove it by ID
msg = "AWS::Logs::ResourcePolicy is not yet supported in GovCloud; removing from template."
cdk.Annotations.of(node).add_warning(msg)
node.node.try_remove_child(node.node.default_child.node.id) Unfortunately, I couldn't find a way to determine the current Partition before I ran out of brain power. Would be nice to add a |
You can create a condition based on new CfnCondition(scope, 'IsGovCloud', {
expression: Fn.conditionEquals(Aws.PARTITION, 'aws-us-gov'),
}); |
I'm not sure if that's correct. I haven't checked GovCloud in awhile but it should be available in |
^ @cmckni3 appreciate the suggestion, but I did try that and unfortunately |
Yeah make sense depending on how you synth. |
Reproduction Steps
Also fails with the resource policy that I need.
Error Log
Environment
Other
This is 🐛 Bug Report
The text was updated successfully, but these errors were encountered: