Skip to content

Connecting GitHub ​

pipeline.source: github builds from a GitHub repository, and a private one is reached through an AWS CodeConnections connection. Setting one up is four steps, two of which have a wrong answer that produces a working-looking connection and a failing build.

This is the procedure for both an organization and a personal account. They differ in one field.

What has to be true ​

Three things, and Keel can verify only the first:

  1. A connection exists and is AVAILABLE, recorded at /keel/connections/github/{owner}.
  2. That connection is bound to a GitHub App installation which can see the repository. Not to a GitHub user — see below.
  3. The account has a GitHub source credential naming that connection. This is what CodeBuild reads when it creates a build project.

keel auth connect github {owner} does 1 and 3. Step 2 happens in a browser and is the one that goes wrong.

The owner comes from keel.yml ​

Keel derives it from pipeline.repo:

yaml
pipeline:
  source: github
  repo: devtide-llc/keel-test    # owner is "devtide-llc"
  branch: main

That owner names the connection (keel-devtide-llc) and keys the SSM parameter. It is a label, not a boundary. CreateConnection takes only a name and a provider type — AWS is never told which organization you meant, and nothing constrains where the App is installed. A personal repo works the same way with repo: {username}/{repo}.

Procedure ​

1. Install the App where the repository is ​

Do this first. It removes the step where the wrong answer is easiest to give.

If you have installations you do not want used, remove them now. The AWS console lists installations by opaque numeric ID rather than by account name, so the reliable way to pick the right one is for it to be the only one.

2. Create the connection ​

bash
keel auth connect github {owner}

It creates the connection PENDING, records the ARN in SSM, prints a console URL and waits. An existing connection is reused rather than duplicated.

3. Authorize, in the browser ​

Open the printed URL, choose the connection, and select Update pending connection. Two screens follow and only the second one decides anything:

github.com/login/oauth/authorize — "AWS Connector for GitHub wants access to your GitHub account", verifying your GitHub identity. There is no organization option here and that is correct: identities are personal. Click Authorize.

Back in the AWS console — "GitHub connection settings". This is the decision:

App Installation - optional
Install GitHub App to connect as a bot. Alternatively, leave it blank to
connect as a GitHub user, which can be used in AWS CodeBuild projects.

Choose the installation. Do not leave it blank. The field is marked optional and the help text says a blank one works with CodeBuild; in practice a user-bound connection reaches AVAILABLE and then fails every CreateProject. If the picker is empty, use Install a new app — GitHub then shows an account picker, and that is where you choose the organization rather than your personal account.

Then Connect.

4. Apply ​

bash
keel up --env {env}

keel auth connect has already registered the account's GitHub source credential, so nothing else is needed.

Verifying, and what Keel cannot tell you ​

AVAILABLE means an installation is bound. It does not say which one. No CodeConnections API returns the install target — not GetConnection, and not CreateRepositoryLink, which accepts an owner and repository as plain strings and does no reachability check at all. So Keel reports the status it can read and names where you check the rest:

bash
# the connection Keel will use
aws ssm get-parameter --name /keel/connections/github/{owner} \
  --query Parameter.Value --output text

# the account's source credential — CodeBuild reads this, not the project
aws codebuild list-source-credentials

The installation itself is only visible on GitHub, at the organization's or your own installations page.

When it goes wrong ​

OAuthProviderException: User is not authorized to access connection {arn} ​

Raised by CreateProject during keel up. The message names the connection and is usually not about the connection — which is what makes it expensive. Check in this order:

  1. The account's source credential. aws codebuild list-source-credentials should return a GITHUB entry. Absent, re-run keel auth connect github {owner}, which registers it, or:
    bash
    aws codebuild import-source-credentials --server-type GITHUB \
      --auth-type CODECONNECTIONS --token {connection-arn}
  2. Whether the connection is bound to a user rather than an installation. Not readable from AWS. If the App Installation field was left blank in step 3, delete the connection, delete /keel/connections/github/{owner}, and redo steps 2–3.
  3. Whether the installation can see the repository — the organization's installations page, Repository access.

A stale keel-admin policy is worth ruling out once, and rarely the answer:

bash
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::{account}:role/keel-admin \
  --action-names codestar-connections:PassConnection \
  --resource-arns {connection-arn} --query 'EvaluationResults[0].EvalDecision'

implicitDeny means re-run keel auth setup, which rewrites the policies.

The build creates and then fails to clone ​

The project exists, so the credential is right; the installation cannot see the repository. Check Repository access on the installation.

keel auth connect says the connection already exists and exits ​

Reuse rather than repair, by design — but it does re-register the account credential on every run, so it is the right thing to try first. If the connection itself is wrong, delete it and the SSM parameter before re-running:

bash
aws codeconnections delete-connection --connection-arn {arn}
aws ssm delete-parameter --name /keel/connections/github/{owner}

Why CodeBuild works this way ​

Worth knowing, because the obvious design is the wrong one and reads as correct.

A CodeBuild project can carry a per-source auth block naming a connection, and CODECONNECTIONS is a valid type there. It does not work: CreateProject fails with the OAuthProviderException above while the connection, the caller's PassConnection, the service role's UseConnection and the App installation are all correct. Established by creating one project twice with the same service role, differing only in that block — without it the project is created, with it the call fails.

What CodeBuild reads is ImportSourceCredentials: one credential per account, per region, per server type. Keel writes it from keel auth connect rather than from an application's stack, because two applications in one account would otherwise contend for a single resource and either one's keel destroy would take the other's builds with it — the same reason the account-wide DynamoDB tables are not in the stack.

The consequence to keep in view: that credential is account-wide, so connecting a second owner overwrites it. One GitHub account or organization per AWS account and region, for now.

No connection at all ​

A public repository clones without one, and keel up says so rather than failing. pipeline.source: codecommit avoids GitHub entirely — keel up creates the repository and keel deploy pushes to it — which is also the quickest way to get an environment up while a connection problem is being sorted out.

Last updated:

Keel — the missing platform layer for AWS.