Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 92 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
# Aembit Credentials (GitHub Action)

## Overview

This action retrieves temporary credentials from Aembit for use in your GitHub workflows. It enables secure, secretless access to external systems like cloud providers or APIs by dynamically fetching scoped credentials at runtime. This helps improves security within CI/CD pipelines.

**Note: this is an alpha release, it is not yet officially supported.**
## Requirements

### Workflow Permissions

> [!IMPORTANT]
> This Action retrieves an OIDC token for your workflow from GitHub to attest its
> identity with Aembit. Your workflow must have the following permission for it to work.

```yaml
permissions:
id-token: write
```

### Aembit Configuration

In Aembit, your Client Workload must use the `GitHub ID Token Repository` identifier,
in the format `org-name/repository-name`. We plan to add support for the `GitHub ID Token Subject`
identifier in future releases.

The Trust Provider in your Access Policy must be of type `GitHub Action ID Token`, using a `repository` Match Rule
with a value that includes the `org/repository` of your workflow. Other Match Rule attributes may work but have not been
tested.

## Usage

Expand All @@ -17,8 +39,8 @@ This action retrieves temporary credentials from Aembit for use in your GitHub w
# This is a required field.
client-id: ''

# Specifies the type of credential to retrieve from Aembit.
# Valid values are ApiKey and Unknown.
# Specifies the type of credential to retrieve from Aembit.
# Valid values are: ApiKey, UsernamePassword, OAuthToken, GoogleWorkloadIdentityFederation, AwsStsFederation
# This is a required field.
credential-type: ''

Expand All @@ -36,11 +58,76 @@ This action retrieves temporary credentials from Aembit for use in your GitHub w
```

### Outputs

The outputs available depend on the `credential-type` specified:

#### ApiKey
```yaml
outputs:
# This output is set by the actions if the credential-type is ApiKey.
# API key credential
# Usage: ${{ steps.step-id.outputs.api-key }}
api-key: '****'
```

<b>Note:</b> All the outputs generated by this action are GitHub masked secrets.
#### UsernamePassword
```yaml
outputs:
# Username credential
# Usage: ${{ steps.step-id.outputs.username }}
username: '****'

# Password credential
# Usage: ${{ steps.step-id.outputs.password }}
password: '****'
```

#### OAuthToken
```yaml
outputs:
# OAuth token credential
# Usage: ${{ steps.step-id.outputs.token }}
token: '****'
```

#### GoogleWorkloadIdentityFederation
```yaml
outputs:
# Google Workload Identity Federation token
# Usage: ${{ steps.step-id.outputs.token }}
token: '****'
```

#### AwsStsFederation
```yaml
outputs:
# AWS Access Key ID
# Usage: ${{ steps.step-id.outputs.aws-access-key-id }}
aws-access-key-id: '****'

# AWS Secret Access Key
# Usage: ${{ steps.step-id.outputs.aws-secret-access-key }}
aws-secret-access-key: '****'

# AWS Session Token
# Usage: ${{ steps.step-id.outputs.aws-session-token }}
aws-session-token: '****'
```

> [!NOTE]
> All the outputs generated by this action are GitHub masked secrets.

## Troubleshooting

If you are getting the error

```
Error: Invalid or currently unsupported credential type: Unknown
```

then Aembit cannot connect your GitHub workflow with an access policy that identifies a credential to return. Some
things to double-check in your configuration are:

* the Client Workload in Aembit has the right `org/repository` identifier for your workflow
* the Trust Provider in Aembit allows the `org/repository` for your workflow
* the `credential-type` value in the Action config matches the type of Credential Provider in your Access Policy
* the `server-host` and `server-port` values in the Action config match the Server Workload in your Access Policy
29 changes: 27 additions & 2 deletions __test__/access-token.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { setupServer } from "msw/node";
import { v4 as uuidv4 } from "uuid";
import { afterAll, afterEach, beforeAll, describe, it } from "vitest";
import { getAccessToken } from "../src/access-token";
import {
edgeApiAuthHandler,
edgeApiGetCredentialsHandlerResponse400,
edgeApiGetCredentialsHandlerResponse500,
} from "./gen/handlers";
} from "../gen/handlers";
import { getAccessToken } from "../src/access-token";

const server = setupServer(edgeApiAuthHandler());

Expand Down Expand Up @@ -55,4 +55,29 @@ describe("getAccessToken", () => {
getAccessToken(reqBody.clientId, reqBody.idToken, reqBody.domain),
).rejects.toThrowError();
});

it("sends Content-Type: application/json header", async ({ expect }) => {
let capturedHeaders: Headers | null = null;

server.use(
edgeApiAuthHandler(async (info) => {
capturedHeaders = info.request.headers;
return new Response(
JSON.stringify({
accessToken: "test-token-12345",
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
},
);
}),
);

await getAccessToken(reqBody.clientId, reqBody.idToken, reqBody.domain);

expect(capturedHeaders?.get("Content-Type")).toBe("application/json");
});
});
Loading