CDK Unable to Add CodeStarNotification to CodePipeline - amazon-web-services

I use CDK to deploy a codepipeline. It works fine until I try to add notification for codepipeline success/fail events. It gives CREATE_FAILED error with message Resource handler returned message: "Invalid request provided: AWS::CodeStarNotifications::NotificationRule" (RequestToken: bb566fd0-1ac9-5d61-03fe-f9c27b4196fa, HandlerErrorCode: InvalidRequest). What could be the reason? Thanks.
import * as codepipeline from "#aws-cdk/aws-codepipeline";
import * as codepipeline_actions from "#aws-cdk/aws-codepipeline-actions";
import * as codestar_noti from "#aws-cdk/aws-codestarnotifications";
import * as sns from "#aws-cdk/aws-sns";
const pipeline = new codepipeline.Pipeline(...);
const topicArn = props.sns_arn_for_developer;
const targetTopic = sns.Topic.fromTopicArn(
this,
"sns-notification-topic",
topicArn
);
new codestar_noti.NotificationRule(this, "Notification", {
detailType: codestar_noti.DetailType.BASIC,
events: [
"codepipeline-pipeline-pipeline-execution-started",
"codepipeline-pipeline-pipeline-execution-failed",
"codepipeline-pipeline-pipeline-execution-succeeded",
"codepipeline-pipeline-pipeline-execution-canceled",
],
source: pipeline,
targets: [targetTopic],
});
Here is the snippet of generated cloudformation tempalte.
"Notification2267453E": {
"Type": "AWS::CodeStarNotifications::NotificationRule",
"Properties": {
"DetailType": "BASIC",
"EventTypeIds": [
"codepipeline-pipeline-pipeline-execution-started",
"codepipeline-pipeline-pipeline-execution-failed",
"codepipeline-pipeline-pipeline-execution-succeeded",
"codepipeline-pipeline-pipeline-execution-canceled"
],
"Name": "sagemakerbringyourownNotification36194CEC",
"Resource": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":codepipeline:ap-southeast-1:305326993135:",
{
"Ref": "sagemakerbringyourownpipeline0A8C43B1"
}
]
]
},
"Targets": [
{
"TargetAddress": "arn:aws:sns:ap-southeast-1:305326993135:whitespace_alerts",
"TargetType": "SNS"
}
]
},
"Metadata": {
"aws:cdk:path": "sagemaker-bring-your-own/Notification/Resource"
}
},

FWIW, I got the exact same error "Invalid request provided: AWS::CodeStarNotifications::NotificationRule" from a CDK app where the Topic was created (not imported). It turned out to be a transient issue, because it succeeded the second time without any changes. I suspect it was due to a very large ECR image which was build the first time as part of the deploy and which took quite some time. My speculation is that the Topic timed out and got into some kind of weird state waiting for the NotificationRule to be created.

This is because imported resources cannot be modified. As you pointed out in the comments, setting up the notification involves modifying the Topic resource, specifically its access policy.
Reference: https://docs.aws.amazon.com/cdk/v2/guide/resources.html#resources_importing

I was able to solve this by doing the following in that order:
First removing the below statement from the resource policy of the SNS topic.
Then deploying the stack(which interestingly doesn't add anything to the resource policy)
Once the stack deployment finishes, update the resource policy manually to add the below statement.
{
"Sid": "AWSCodeStarNotifications_publish",
"Effect": "Allow",
"Principal": {
"Service": "codestar-notifications.amazonaws.com"
},
"Action": "SNS:Publish",
"Resource": "arn:aws:sns:ap-south-1:xxxxxxxxx:test"
}

Related

SSM Document not working LAMBDA -> SSM- > Event bridge , im stuck and out of ideas

So I've tried setting up a LAMBDA function using python 3.9, which calls my SSM Document which will restart "Coldfusion 2018 application server" within windows, if the cloudwatch alert name is triggered. I have it set in eventbridge to alarm state change which means everything the domain goes down "Coldfusion service stopped" it should run the SSM document and the powershell script. But nothing is working at all and ive tried practically everything i know of.
Below are my default roles for LAMBDA + Inline Policy, along with my LAMBDA function, my SSM document and my eventbridge.
My Lambda default role assigned is :
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:ap-southeast-2:727665054500:*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:ap-southeast-2:727665054500:log-group:/aws/lambda/johntest:*"
]
}
]
}
And my Inline policy attached to my default role, to allow SSM is:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "ssm:SendCommand",
"Resource": "*"
}
]
}
Lambda function:
import os
import boto3
import json
ssm = boto3.client('ssm')
def lambda_handler(event, context):
InstanceId = 'i-06692c60000c89460'
ssmDocument = 'johntest'
log_group = os.environ['AWS_LAMBDA_LOG_GROUP_NAME']
targetInstances = [InstanceId]
response = ssm.send_command(
InstanceIds=targetInstances,
DocumentName=ssmDocument,
DocumentVersion='$DEFAULT',
CloudWatchOutputConfig={
'CloudWatchLogGroupName': log_group,
'CloudWatchOutputEnabled': True
}
)
EventBridge (CloudWatch events) which is the trigger for lambda
{
"source": [
"aws.cloudwatch"
],
"detail-type": [
"CloudWatch Alarm State Change"
],
"detail": {
"alarmName": [
"TASS-john2-Testing-SiteDown for domain https://johntest.tassdev.cloud/tassweb"
],
"state": {
"value": [
"ALARM"
]
},
"previousState": {
"value": [
"OK"
]
}
}
}
SSM document to run the PowerShell script In SSM when you create an initial document, I selected the command/session document which may be wrong? Do I need to make an automation document? If so can someone show me the correct code/syntax please?
---
schemaVersion: "2.2"
description: "Example document"
parameters:
Message:
type: "String"
description: "Example parameter"
default: "Hello World"
mainSteps:
- action: "aws:runPowerShellScript"
name: "example"
inputs:
timeoutSeconds: '600'
runCommand:
- Restart-Service -DisplayName "ColdFusion 2018 Application Server"
I tried setting up the lambda function, with my instance ID/SSM document name, and the trigger is event bridge, which is set to my CloudWatch alarm based on state change. I cannot get the SSM document to trigger my window service "coldfusion" at all.
I have pasted my above code for the eventbridge/ssm document/lambda and even my default lambda role/inline policy which still doesn't seem to work. I also have the SSM agent installed on my instance but still nothing.
EDIT: Just went to Systems Manager, and clicked run command and it ran the powershell script and started up the coldfusion service, but why isn't it triggering from the CloudWatch alarm?
Cheers.

Step Function with EventBridge task `"NotAuthorizedForSourceException"`

Background
I'm creating a Step Function state machine that starts an AWS CodeBuild once a defined AWS CodePipeline has an execution status of SUCCEED. I'm using the .waitForTaskToken feature within the Step Function to wait on the CodePipeline to succeed via a CloudWatch event. Once the pipeline succeeds, the event sends back the token to the step function and runs the CodeBuild.
Here's the step function definition:
{
"StartAt": "PollCP",
"States": {
"PollCP": {
"Next": "UpdateCP",
"Parameters": {
"Entries": [
{
"Detail": {
"Pipeline": [
"bar-pipeline"
],
"State": [
"SUCCEEDED"
],
"TaskToken.$": "$$.Task.Token"
},
"DetailType": "CodePipeline Pipeline Execution State Change",
"Source": "aws.codepipeline"
}
]
},
"Resource": "arn:aws:states:::events:putEvents.waitForTaskToken",
"Type": "Task"
},
"UpdateCP": {
"End": true,
"Parameters": {
"ProjectName": "foo-project"
},
"Resource": "arn:aws:states:::codebuild:startBuild.sync",
"Type": "Task"
}
}
}
The permissions for the step function:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": "codebuild:StartBuild",
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": "codepipeline:*",
"Resource": "*"
}
]
}
and arn:aws:iam::aws:policy/CloudWatchEventsFullAccess
Problem
The cloudwatch event within the step function returns the error:
Error
EventBridge.FailedEntry
Cause
{
"Entries": [
{
"ErrorCode": "NotAuthorizedForSourceException",
"ErrorMessage": "Not authorized for the source."
}
],
"FailedEntryCount": 1
}
Attempts:
Modify the associated Codepipeline and Codebuild role to have step function permission to send task statuses. Specifically, the permission is:
{
"Effect": "Allow",
"Action": [
"states:SendTaskSuccess",
"states:SendTaskFailure",
"states:SendTaskHeartbeat"
],
"Resource": "*"
}
Got the same original error mentioned above.
Modify the associated Step Function machine's permission to have full access to all step function actions and resources. Got the same original error mentioned above.
Test the event rule specified in the PollCP step function task with the default AWS EventBridge bus. The event was:
{
"version": "0",
"detail-type": "CodePipeline Pipeline Execution State Change",
"source": "aws.codepipeline",
"account": "123456789012",
"time": "2021-06-14T00:44:41Z",
"region": "us-west-2",
"resources": [],
"detail": {
"pipeline": "<pipeline-arn>",
"state": "SUCCEED"
}
}
The event outputted the same error mentioned above. This probably means the error is strictly related to the event entry mentioned in the code snippet above.
Are you trying to trigger your State Machine using CloudWatch event when a CodePipeline pipeline completes/succeeds?
If so, you cannot define your trigger in your state machine.
The integration with EventBridge is not so that state machine can be triggered by events. Rather it is to Publish events to an event bus from your state machine or workflow.
Read more here: https://aws.amazon.com/blogs/compute/introducing-the-amazon-eventbridge-service-integration-for-aws-step-functions/
So I suggest you create a CloudWatch rule and target your state machine instead.
If you want to use the waitForTaskToken pattern. You will have to explicitly return that token with a send_task_success API call (sample below for python/boto3).
sfn.send_task_success(
taskToken=task_token,
output=json.dumps(some_optional_payload)
)
This means that, when the step executes, it will publish the event to EventBridge bus. You will have to detect this event outside your state machine, most likely with an CloudWatch event rule. Then trigger a lambda function from the rule. The lambda function performs the send_task_success API call which restarts/continues your workflow/state machine.
In my opinion, that is just unnecessary. Like I said, you can simply watch for pipeline execution state changes uing CW event rule, trigger your state machine, and your state machine starts with the CodeBuild stage.
Side note: It's nice to see people using Step Functions for CI/CD pipeline. It's just got more flexibility and ability to do complex branching strategies. Will probably do a blog post around this soon.
Your CodeBuild service role will need permission to use the states:SendTask* (Success, Failure, and Heartbeat) actions so that it can notify the state machine. This page in the docs has more details.

Cannot assume role by code pipeline on code pipeline action AWS CDK

I have been playing with AWS CDK and was working on building a code pipeline stack on my AWS educate account. The user that I am using has enough permission to access and use the code pipeline. My problem is, AWS CDK generates a role for the code pipeline action whose Principle is ARN of the root account. So it doesn't have the permission to perform assume the role on the root account.
Action code:
{
stageName: "Build",
actions: [
new codepipelineActions.CodeBuildAction(
{
actionName: "Build",
input: sourceOutput,
project: builder
}
)
]
}
Cloudformation Template Output:
"devPipelineBuildCodePipelineActionRole8696D056": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::",
{
"Ref": "AWS::AccountId"
},
":root"
]
]
}
}
}
],
"Version": "2012-10-17"
}
},
"Metadata": {
"aws:cdk:path": "PipeLineStack/dev-Pipeline/Build/Build/CodePipelineActionRole/Resource"
}
}
...
{
"Actions": [
{
"ActionTypeId": {
"Category": "Build",
"Owner": "AWS",
"Provider": "CodeBuild",
"Version": "1"
},
"Configuration": {
"ProjectName": {
"Ref": "BuildAndTestB9A2F419"
}
},
"InputArtifacts": [
{
"Name": "SourceOutput"
}
],
"Name": "Build",
"RoleArn": {
"Fn::GetAtt": [
"devPipelineBuildCodePipelineActionRole8696D056",
"Arn"
]
},
"RunOrder": 1
}
],
"Name": "Build"
}
This will throw the error:
arn:aws:iam::acount_id:role/PipeLineStack-devPipelineRole5B29FEBC-1JK24J0K5N1UG is not authorized to perform AssumeRole on role arn:aws:iam::acount_id:
role/PipeLineStack-devPipelineBuildCodePipelineActionRo-17ETJU1KZCCNQ (Service: AWSCodePipeline; Status Code: 400; Error Code: InvalidStructureException; Req
uest ID: c8c8af89-2409-4cc1-aad8-4de553a1764f; Proxy: null)
If I remove the RoleArn from the Action and execute the template it works.
My question is, How do I prevent CDK to prevent adding default role with Principle using the root account or a work around to it?
It looks like actions are not allowed to assume any role in AWS Educate currently. So to have a workaround and remove the manual overhead, use CDK L1 Constructs to modify the generated cloud formation.
The pipeline can be created like:
// Custom role to pass in to pipeline
const pipeLineRole = new iam.Role(this, "CodePipeLineRole", {
assumedBy: new iam.ServicePrincipal("codepipeline.amazonaws.com"),
});
pipeLineRole.addToPolicy(
// Required policy for each aciton to run
)
const pipeline = new codepipeline.Pipeline(this, "Pipeline", {
role: pipeLineRole,
stages: [
// ...
{
actions: [action1, action2],
},
// ...
],
});
// Altering cloudformation to remove role arn from actions
const pipelineCfn = pipeline.node.defaultChild as cdk.CfnResource;
// addDeletionOverride removes the property from the cloudformation itself
// Delete action arn for every stage and action created
pipelineCfn.addDeletionOverride("Properties.Stages.1.Actions.0.RoleArn");
pipelineCfn.addDeletionOverride("Properties.Stages.2.Actions.0.RoleArn");
pipelineCfn.addDeletionOverride("Properties.Stages.3.Actions.0.RoleArn");
This is a workaround, it works, but there are still unwanted and dangling policies and roles created that have not been assigned to any service which had been created for individual actions.
The following code in pipeline configuration:
"RoleArn": {
"Fn::GetAtt": [
"devPipelineBuildCodePipelineActionRole8696D056",
"Arn"
]
},
... means when CodePipeline service will invoke the "Build" action, it will "assume" the role "devPipelineBuildCodePipelineActionRole8696D056" but this role does not have a trust policy with "codepipeline.amazonaws.com" service hence the error.
The 'RoleArn' property under the action is useful when you have a cross account action (CodeBuild project is in another account) so unless that is the case, it is better to drop this property.
We will need to see the cdk code to answer your question:
How do I prevent CDK to prevent adding default role with Principle using the root account or a work around to it?
Subesh's code works in removing RoleArn. But in my AWS env, RoleArn is still required. I am trying to replaced it with an existing role, but it still only removes RoleArn. What is wrong with my code?
pipelineCfn.addDeletionOverride("Properties.Stages.1.Actions.0.RoleArn");
pipelineCfn.addDeletionOverride("Properties.Stages.2.Actions.0.RoleArn");
pipelineCfn.addPropertyOverride(
"Properties.Stages.1.Actions.0.RoleArn",
pipeline_role_arn
);
pipelineCfn.addPropertyOverride(
"Properties.Stages.2.Actions.0.RoleArn",
pipeline_role_arn
);

How can I recreate lambda function via cloudformation?

I am using serverless to manage IaC which uses cloudformation internally. There are a number of lambdas and roles defined in serverless.yml. It works very well until I tried to sls remove all resources and sls deploy again. After doing that, I get an error when run lambdas: The role defined for the function cannot be assumed by Lambda. (Service: AWSLambda; Status Code: 403; Error Code: AccessDeniedException; Request ID: 0879c203-bec7-480b-81c6-4c7a61e2cb15.
The error says lambda doesn't have permission however, it works if I change the lambda role to something else and change it back. It seems that lambda's role still references to the deprecated one.
I wonder what the proper way to do remove followed by deploy.
The role is:
{
"Role": {
"Path": "/",
"RoleName": "getSiteHandlerRole",
"RoleId": "xxxxx",
"Arn": "arn:aws:iam::115136697128:role/getSiteHandlerRole",
"CreateDate": "2020-07-27T03:37:18Z",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Description": "",
"MaxSessionDuration": 3600,
"Tags": [
{
"Key": "STAGE",
"Value": "user"
}
]
}
}

My CloudWatch Event rule doesn't trigger my CodePipeline pipeline

I'm having some issues with AWS CloudWatch Events.
I'm creating a CodePipeline CI pipeline which have a CodeCommit repository as the Source, a CodeBuild project as the Build/Test phase (then, it deploys to Lambda, but the problem isn't there).
We have multiple projects and we are going to push multiple other projects. So, I created a script that manages the AWS CI stuff (i.e. creating a pipeline, a CodeBuild project, ... AND a CloudWatch Events rule, linked to the pipeline).
The first time I push my code, it works. But then, the process stop getting triggered by the push on CodeCommit.
I found a solution (but NOT the one I want) : I just have to modify the pipeline, modify the stage (Source), not touching anything, and saving the null modification : and it works (before saving, it ask the authorization to create a CloudWatch Events rule associated with this pipeline).
Does somebody encountered this issue ? What did you do to bypass it ?
I really want to make a 100% automated CI, I don't want to go to the AWS Console each time my team create a new repository or push a new branch on an existing repository.
EDIT :
Here is the JSON of my CloudWatch Events rule :
{
"Name": "company-ci_codepipeline_project-stage",
"EventPattern": "cf. second JSON",
"State": "ENABLED",
"Arn": "arn:aws:events:region:xxx:rule/company-ci_codepipeline_project-stage",
"Description": "CloudWatch Events rule to automatically trigger the needed pipeline from every push to project repository, on the stage branch on CodeCommit."
}
And here is the EventPattern JSON :
{
"source": [
"aws.codecommit"
],
"detail-type": [
"CodeCommit repository state change"
],
"resources": [
"arn:aws:codecommit:region:xxx:project"
],
"detail": {
"event": [
"referenceCreated",
"referenceUpdated"
],
"referenceType": [
"branch"
],
"referenceName": [
"stage"
]
}
}
I've found this issue is typically related to the event rule/target/role configuration. If you don't have a target associated with your rule, you will NOT see the event invoked when reviewing metrics. Since your EventPattern looks correct, I'm thinking the target might be your issue.
You should have a configured target that looks something like:
{
"Rule": "company-ci_codepipeline_project-stage",
"Targets": [
{
"RoleArn": "arn:aws:iam::xxx:role/cwe-codepipeline",
"Id": "ProjectPipelineTarget",
"Arn": "arn:aws:codepipeline:region:xxx:your-pipeline"
}
]
}
If that seems all good, I'd next check that the role associated with the target is granting the correct permissions. My role looks something like:
{
"Role": {
"Description": "Allows CloudWatch Events to invoke targets and perform actions in built-in targets on your behalf.",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "events.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
},
"MaxSessionDuration": 3600,
"RoleId": "xxxx",
"CreateDate": "2018-08-06T20:56:19Z",
"RoleName": "cwe-codepipeline",
"Path": "/",
"Arn": "arn:aws:iam::xxx:role/cwe-codepipeline"
}
}
And it has an inline policy of:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codepipeline:StartPipelineExecution"
],
"Resource": [
"arn:aws:codepipeline:*:xxx:*"
]
}
]
}
For reference, check out this documentation