codebuild: project creation fails when GitHub source webhook is enabled
Describe the bug
CloudFormation throws an error when we try to create a CodeBuild project with GitHub webhook is configured.
16:13:04 | CREATE_FAILED | AWS::CodeBuild::Project | MyProject2B52B17CC Failed to call CreateWebhook, reason: Access denied to connection arn:aws:codeconnections:us-west-2:REDACTED:connection/REDACTED (Service: AWSCodeBuild; Status Cod e: 400; Error Code: InvalidInputException; Request ID: REDACTED; Proxy: null)
Regression Issue
- [ ] Select this option if this issue appears to be a regression.
Last Known Working CDK Version
No response
Expected Behavior
CodeBuild project is successfully created.
Current Behavior
CloudFormation throws an error when creating a project.
Reproduction Steps
- First, create a GitHub app connection from the management console. https://docs.aws.amazon.com/codebuild/latest/userguide/connections-github-app.html
- Deploy the below stack, and you'll get an error. (replace
YOUR_GITHUB_NAMEandYOUR_REPOSITORY_NAMEto an existing repo.)
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
export class CodebuildGhaCdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const project = new codebuild.Project(this, 'MyProject', {
source: codebuild.Source.gitHub({
owner: 'YOUR_GITHUB_NAME',
repo: 'YOUR_REPOSITORY_NAME',
webhookFilters: [codebuild.FilterGroup.inEventOf(codebuild.EventAction.WORKFLOW_JOB_QUEUED)],
}),
});
// uncommenting this makes it work
// project.role!.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
}
}
Possible Solution
https://github.com/aws/aws-cdk/issues/31726#issuecomment-2413937735
This was a problem of both permission and dependency.
Additional Information/Context
When I added Administrator permission to the project, CFn successfully deployed the project. But not sure exactly which permission is missing.
// WORKS
project.role!.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
Allowing codeconnections did not work:
// NOT WORK
project.addToRolePolicy(
new PolicyStatement({
actions: [
'codeconnections:*',
'codestar-connections:*',
],
resources: ['*'],
})
);
CDK CLI Version
2.162.0
Framework Version
No response
Node.js Version
20
OS
macos
Language
TypeScript
Language Version
No response
Other information
We need to enable webhook to use a CodeBuild-hosted GitHub Actions runner.
@tmokmss Good afternoon. Somehow, I'm unable to reproduce issue at my end using CDK version 2.162.0 (build c8d7dd3):
import * as cdk from 'aws-cdk-lib';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
export class CdktestStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// This should be one time task.
new codebuild.GitHubSourceCredentials(this, 'CodeBuildGitHubCreds', {
accessToken: cdk.SecretValue.unsafePlainText('<<REDACTED>>')
});
const project = new codebuild.Project(this, 'MyProject', {
source: codebuild.Source.gitHub({
owner: 'mygithubname',
repo: 'testrepo',
webhookFilters: [codebuild.FilterGroup.inEventOf(codebuild.EventAction.WORKFLOW_JOB_QUEUED)],
}),
});
}
}
gives below error during deployment:
✨ Synthesis time: 4.25s
CdktestStack: start: Building 551fa8c3d398f2112a97f5c3b96f2d1da537f7c06ff3f1345a1a3e63aa0377ad:139480602983-us-east-2
CdktestStack: success: Built 551fa8c3d398f2112a97f5c3b96f2d1da537f7c06ff3f1345a1a3e63aa0377ad:139480602983-us-east-2
CdktestStack: start: Publishing 551fa8c3d398f2112a97f5c3b96f2d1da537f7c06ff3f1345a1a3e63aa0377ad:139480602983-us-east-2
CdktestStack: success: Published 551fa8c3d398f2112a97f5c3b96f2d1da537f7c06ff3f1345a1a3e63aa0377ad:139480602983-us-east-2
Stack undefined
CdktestStack: deploying... [1/1]
CdktestStack: creating CloudFormation changeset...
✅ CdktestStack
✨ Deployment time: 55.54s
Stack ARN:
arn:aws:cloudformation:us-east-2:<<ACCOUNT-ID>>:stack/CdktestStack/1079e520-8a77-11ef-89fa-020707ed96ab
✨ Total time: 59.79s
I'm unsure if you added necessary permissions mentioned at https://docs.aws.amazon.com/codebuild/latest/userguide/connections-github-app.html#connections-github-role-access to the IAM role used to deploy CDK stack.
Thanks, Ashish
@ashishdhingra Thank you for the investigation!
Can you try GitHub App connections instead of a PAT credential? You also need to set the connection as an account level credential. With this configuraiton, the issue should reproduce.
And thank you for pointing out the necessary permission. It seems we need to create the policy before creating a project. So I confirmed something like this worked:
const project = new codebuild.Project(this, 'MyProject', {
source: codebuild.Source.gitHub({
owner: 'redacted',
repo: 'redacted',
webhookFilters: [codebuild.FilterGroup.inEventOf(codebuild.EventAction.WORKFLOW_JOB_QUEUED)],
}),
});
const codeConnectionPolicy = new Policy(this, 'CodeConnectionPolicy', {
statements: [
new PolicyStatement({
actions: ['codeconnections:GetConnectionToken', 'codeconnections:GetConnection'],
resources: ['*'],
}),
],
});
project.role!.attachInlinePolicy(codeConnectionPolicy);
// create the policy before the project
(project.node.defaultChild as cdk.CfnResource).addDependency(codeConnectionPolicy.node.defaultChild as cdk.CfnResource);
I think this should be automatically configured in L2 code, or at least be clearly described in the doc.
I was having a similar issue, however I also needed to update the CfnProject to include the missing Auth
(project.node.defaultChild as CfnProject).addPropertyOverride('Source.Auth', {
Type: 'CODECONNECTIONS',
Resource:
'arn:aws:codeconnections:<region>:<account-id>:connection/<connection-id>',
})
Agree with @tmokmss that the L2 construct should be updated because this use case, which would be very common, is missing from any of the existing constructs
@patrickdorival I configured account level credential to avoid from setting connection per project, but yeah it's disappointing that current L2 doesn't support Source.Auth property. I'll create a seprarate issue for this.
edit) We already have this one: #31236
Yes, I saw that issue as well. Seems to be a few things missing from the L2 construct when you want to use Code Connections for your auth
Is this only being picked up if there is lot of thumbs up?
I actually got this all working (finally).
Here is the setup I am using (python)
# This one is technically in a different stack as it is "shared"
# this is also configured as an installation vs a user-auth.
self.github_connection = code_connections.CfnConnection(
self, 'GitHubConnection',
connection_name='My Github Connection',
provider_type='GitHub',
)
# Really unsure if this is even needed.. We had it created for out GitLab setup (non-CDK)
source_credential = code_build.CfnSourceCredential(
self, 'MySourceCredential',
auth_type='CODECONNECTIONS',
server_type='GITHUB',
token=self.github_connection.attr_connection_arn,
)
my_project = code_build.Project(
self, 'MyProject',
description='Some awesome project',
environment=code_build.BuildEnvironment(
compute_type=code_build.ComputeType.SMALL,
privileged=True,
build_image=code_build.LinuxBuildImage.from_code_build_image_id(
'aws/codebuild/amazonlinux2-x86_64-standard:5.0'),
environment_variables=dict(
# Some ENV variables
),
build_spec=code_build.BuildSpec.from_source_filename('ci/buildspec.yml'),
source=code_build.Source.git_hub(
owner='mygithuborg',
repo='mygithubrepo',
branch_or_ref='refs/heads/main',
webhook_filters=[
code_build.FilterGroup.in_event_of(code_build.EventAction.PUSH).and_branch_is('main')
]
)
)
# this was the required policy for Github connection (more than what GitLab required)
code_connection_policy = iam.Policy(
self, 'MyProjectRoleCodeConnectionPolicy',
statements=[
iam.PolicyStatement(
effect=iam.Effect.ALLOW,
actions=[
# through a lot of jiggling the handle I believe this is the required permission set.
'codeconnections:UseConnection',
'codeconnections:GetConnection',
'codeconnections:GetConnectionToken',
],
resources=[
self.github_connection.attr_connection_arn
]
)
]
)
# Attach the policy to the generated role
my_project.role.attach_inline_policy(code_connection_policy)
# set dependencies to ensure the policy is created BEFORE the project gets created.
# This was one KEY item here otherwise it will ALWAYS fail
my_project.node.default_child.add_dependency(code_connection_policy.node.default_child)
# Finally associate the connection on the project
my_project.node.default_child.add_property_override('Source.Auth', dict(
Type= 'CODECONNECTIONS',
Resource=self.github_connection.attr_connection_arn,
))
We're experiencing the same exact issue as the OP. @urkle 's solution doesn't seem to work in our case. We've unblocked ourselves by manually creating the webhooks, but that's obviously not a long term solution.
@mbparker bummer.. I thought I had the right privileges.. I bet what happened is I had ran it once with codeconnections:* as the allowed actions and it worked. And probably fully destroying the project resource did not remove that webhook.
Having better documentation from AWS as to what privileges are actually needed to do certain things would be immensely helpful. Right now most errors do not even report what privilege is needed to allow them to succeed, which makes triaging and fixing things near impossible.
We're using a very ugly construct to implement this. It's automated but it's ugly. (we're deploying organizational runners)
import { RemovalPolicy, CfnResource } from 'aws-cdk-lib';
import { CfnProject, Project, Source, IBuildImage, ComputeType } from 'aws-cdk-lib/aws-codebuild';
import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs';
import { Policy, PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
export interface GitHubRunnerProjectProps {
runnerName: string;
gitHubOrgName: string;
codeConnectionArn: string;
buildImage: IBuildImage;
computeType: ComputeType;
}
export class GitHubRunnerProject extends Construct {
public readonly project: Project;
constructor(scope: Construct, id: string, props: GitHubRunnerProjectProps) {
super(scope, id);
const { runnerName, gitHubOrgName, codeConnectionArn, buildImage, computeType } = props;
this.project = new Project(this, 'OrgShRunnerCodeBuildProject', {
projectName: runnerName,
source: Source.gitHub({
owner: 'dummy',
repo: 'dummy',
}),
environment: {
buildImage: buildImage,
computeType: computeType,
},
logging: {
cloudWatch: {
logGroup: new LogGroup(this, 'OrgShRunnerCodeBuildProjectLogGroup', {
retention: RetentionDays.ONE_MONTH,
removalPolicy: RemovalPolicy.DESTROY,
}),
},
},
});
const codeConnectionPolicy = new Policy(this, 'CodeConnectionPolicy', {
statements: [
new PolicyStatement({
actions: ['codeconnections:GetConnectionToken', 'codeconnections:GetConnection'],
resources: ['*'],
}),
],
});
this.project.role!.attachInlinePolicy(codeConnectionPolicy);
(this.project.node.defaultChild as CfnResource).addDependency(
codeConnectionPolicy.node.defaultChild as CfnResource,
);
const cfnProject = this.project.node.defaultChild as CfnProject;
cfnProject.addPropertyOverride('Source', {
Type: 'GITHUB',
Location: 'CODEBUILD_DEFAULT_WEBHOOK_SOURCE_LOCATION',
Auth: {
Type: 'CODECONNECTIONS',
Resource: codeConnectionArn,
},
});
cfnProject.addPropertyOverride('Triggers', {
Webhook: true,
ScopeConfiguration: {
Name: gitHubOrgName,
},
FilterGroups: [
[
{
Type: 'EVENT',
Pattern: 'WORKFLOW_JOB_QUEUED',
},
],
],
});
}
}
And calling
new GitHubRunnerProject(this, 'GitHubRunnerAmznLinux2023Arm64Small', {
runnerName: 'yyy',
gitHubOrgName: gitHubOrgName,
codeConnectionArn: codeConnectionArn,
buildImage: LinuxArmBuildImage.AMAZON_LINUX_2023_STANDARD_3_0,
computeType: ComputeType.SMALL,
});
new GitHubRunnerProject(this, 'GitHubRunnerUbuntuExtX86small', {
runnerName: 'xxx',
gitHubOrgName: gitHubOrgName,
codeConnectionArn: codeConnectionArn,
buildImage: LinuxBuildImage.STANDARD_7_0,
computeType: ComputeType.SMALL,
});