Skip to content
Open
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
39 changes: 31 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ This GitHub Action enables you to import secrets from Infisical—whether hosted

## Configuration

- In order to use this, you will need to configure a [Machine Identity](https://infisical.com/docs/documentation/platform/identities/machine-identities) for your project.
- This action supports three ways to authenticate your workflows with Infisical - [AWS IAM Auth](https://infisical.com/docs/documentation/platform/identities/aws-auth), [OIDC](https://infisical.com/docs/documentation/platform/identities/oidc-auth/github) and [universal auth](https://infisical.com/docs/documentation/platform/identities/universal-auth).
- This action supports four ways to authenticate your workflows with Infisical:
- [Universal Auth](https://infisical.com/docs/documentation/platform/identities/universal-auth) - Machine Identity with client ID/secret
- [OIDC Auth](https://infisical.com/docs/documentation/platform/identities/oidc-auth/github) - GitHub OIDC token exchange
- [AWS IAM Auth](https://infisical.com/docs/documentation/platform/identities/aws-auth) - AWS IAM-based authentication
- [Service Token](https://infisical.com/docs/documentation/platform/token) - Project-scoped service tokens

### AWS IAM Auth

Expand All @@ -16,7 +19,7 @@ This GitHub Action enables you to import secrets from Infisical—whether hosted
- Ensure your runner has network access to AWS STS API endpoints.

```yaml
- uses: Infisical/secrets-action@v1.0.9
- uses: Infisical/secrets-action@v1.0.15
with:
method: "aws-iam"
identity-id: "24be0d94-b43a-41c4-812c-1e8654d9ce1e"
Expand Down Expand Up @@ -44,6 +47,22 @@ permissions:
- Get the machine identity's `client_id` and `client_secret` and store them as Github secrets (recommended) or environment variables.
- Set the `client-id` and `client-secret` input parameters.

### Service Token Auth

- Create a service token in your project's Access Control > Service Tokens tab. Refer to the setup guide [here](https://infisical.com/docs/documentation/platform/token).
- Store the service token as a GitHub secret (recommended).
- Set `method` to `service-token` and configure the `service-token` input parameter.

```yaml
- uses: Infisical/secrets-action@v1.0.15
with:
method: "service-token"
service-token: ${{ secrets.INFISICAL_SERVICE_TOKEN }}
domain: "https://app.infisical.com"
env-slug: "dev"
project-slug: "my-project"
```

## Usage

With this action, you can use your Infisical secrets in two ways: as environment variables or as a file.
Expand All @@ -53,7 +72,7 @@ With this action, you can use your Infisical secrets in two ways: as environment
Secrets are injected as environment variables and can be referenced by subsequent workflow steps.

```yaml
- uses: Infisical/secrets-action@v1.0.9
- uses: Infisical/secrets-action@v1.0.15
with:
method: "oidc"
identity-id: "24be0d94-b43a-41c4-812c-1e8654d9ce1e"
Expand All @@ -67,7 +86,7 @@ Secrets are injected as environment variables and can be referenced by subsequen
Exports secrets to a file in your `GITHUB_WORKSPACE`, useful for applications that read from `.env` files.

```yaml
- uses: Infisical/secrets-action@v1.0.9
- uses: Infisical/secrets-action@v1.0.15
with:
method: "oidc"
identity-id: "24be0d94-b43a-41c4-812c-1e8654d9ce1e"
Expand All @@ -90,7 +109,7 @@ steps:

### `method`

**Optional**. The authentication method to use. Defaults to `universal`. Possible values are `universal`, `oidc`, and `aws-iam`
**Optional**. The authentication method to use. Defaults to `universal`. Possible values are `universal`, `oidc`, `aws-iam`, and `service-token`.

### `client-id`

Expand All @@ -106,7 +125,11 @@ steps:

### `oidc-audience`

**Optional**. Custom aud claim for the signed Github ID token
**Optional**. Custom aud claim for the signed Github ID token.

### `service-token`

**Optional**. Infisical Service Token. Only used when `method` is set to `service-token`.

### `project-slug`

Expand Down Expand Up @@ -176,7 +199,7 @@ jobs:
uses: actions/checkout@v4

- name: Setup Infisical Secrets
uses: Infisical/secrets-action@v1.0.12
uses: Infisical/secrets-action@v1.0.15
with:
method: "universal"
domain: "https://<infisical instance url>" # Your internal Infisical domain
Expand Down
12 changes: 9 additions & 3 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ branding:
color: "yellow"
inputs:
method:
description: "The authentication method to use (universal, oidc, aws-iam)"
description: "The authentication method to use (universal, oidc, aws-iam, service-token)"
required: false
default: "universal"
service-token:
description: "Infisical Service Token (only used when method is service-token)"
required: false
client-id:
description: "Machine Identity client ID"
required: false
Expand All @@ -22,8 +25,11 @@ inputs:
description: "Custom aud claim for the signed Github ID token"
required: false
project-slug:
description: "Source project slug"
required: true
description: "Source project slug (ignored if project-id is provided)"
required: false
project-id:
description: "Source project ID (UUID). Takes precedence over project-slug."
required: false
env-slug:
description: "Source environment slug"
required: true
Expand Down
39 changes: 29 additions & 10 deletions dist/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -52770,7 +52770,8 @@ const AWS_IDENTITY_DOCUMENT_URI = "http://169.254.169.254/latest/dynamic/instanc
const AuthMethod = {
Universal: "universal",
Oidc: "oidc",
AwsIam: "aws-iam"
AwsIam: "aws-iam",
ServiceToken: "service-token"
};

const handleError = (err) => {
Expand Down Expand Up @@ -52921,22 +52922,29 @@ const getAwsRegion = () => __awaiter(void 0, void 0, void 0, function* () {
throw err;
}
});
const getRawSecrets = (_a) => __awaiter(void 0, [_a], void 0, function* ({ envSlug, infisicalToken, projectSlug, secretPath, shouldIncludeImports, shouldRecurse, axiosInstance }) {
const getRawSecrets = (_a) => __awaiter(void 0, [_a], void 0, function* ({ envSlug, infisicalToken, projectSlug, projectId, secretPath, shouldIncludeImports, shouldRecurse, axiosInstance }) {
try {
const params = {
secretPath,
environment: envSlug,
include_imports: shouldIncludeImports,
recursive: shouldRecurse,
expandSecretReferences: true
};
// Use workspaceId if project-id is provided, otherwise fall back to workspaceSlug
if (projectId) {
params.workspaceId = projectId;
}
else {
params.workspaceSlug = projectSlug;
}
const response = yield axiosInstance({
method: "get",
url: "/api/v3/secrets/raw",
headers: {
Authorization: `Bearer ${infisicalToken}`
},
params: {
secretPath,
environment: envSlug,
include_imports: shouldIncludeImports,
recursive: shouldRecurse,
workspaceSlug: projectSlug,
expandSecretReferences: true
}
params
});
const keyValueSecrets = Object.fromEntries(response.data.secrets.map(secret => [secret.secretKey, secret.secretValue]));
// process imported secrets
Expand Down Expand Up @@ -52984,11 +52992,13 @@ const main = () => __awaiter(void 0, void 0, void 0, function* () {
const method = core.getInput("method");
const UAClientId = core.getInput("client-id");
const UAClientSecret = core.getInput("client-secret");
const serviceToken = core.getInput("service-token");
const identityId = core.getInput("identity-id");
const oidcAudience = core.getInput("oidc-audience");
const domain = core.getInput("domain");
const envSlug = core.getInput("env-slug");
const projectSlug = core.getInput("project-slug");
const projectId = core.getInput("project-id");
const secretPath = core.getInput("secret-path");
const exportType = core.getInput("export-type");
const fileOutputPath = core.getInput("file-output-path");
Expand Down Expand Up @@ -53031,6 +53041,14 @@ const main = () => __awaiter(void 0, void 0, void 0, function* () {
});
break;
}
case AuthMethod.ServiceToken: {
if (!serviceToken) {
throw new Error("Missing service token for service-token auth");
}
// Service tokens are used directly as Bearer tokens - no login required
infisicalToken = serviceToken;
break;
}
default:
throw new Error(`Invalid authentication method: ${method}`);
}
Expand All @@ -53040,6 +53058,7 @@ const main = () => __awaiter(void 0, void 0, void 0, function* () {
envSlug,
infisicalToken,
projectSlug,
projectId,
secretPath,
shouldIncludeImports,
shouldRecurse
Expand Down
2 changes: 1 addition & 1 deletion dist/index.cjs.map

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export const AWS_IDENTITY_DOCUMENT_URI = "http://169.254.169.254/latest/dynamic/
export const AuthMethod = {
Universal: "universal",
Oidc: "oidc",
AwsIam: "aws-iam"
}
AwsIam: "aws-iam",
ServiceToken: "service-token"
}
11 changes: 11 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ const main = async () => {
const method = core.getInput("method");
const UAClientId = core.getInput("client-id");
const UAClientSecret = core.getInput("client-secret");
const serviceToken = core.getInput("service-token");
const identityId = core.getInput("identity-id");
const oidcAudience = core.getInput("oidc-audience");
const domain = core.getInput("domain");
const envSlug = core.getInput("env-slug");
const projectSlug = core.getInput("project-slug");
const projectId = core.getInput("project-id");
const secretPath = core.getInput("secret-path");
const exportType = core.getInput("export-type");
const fileOutputPath = core.getInput("file-output-path");
Expand Down Expand Up @@ -84,6 +86,14 @@ const main = async () => {
});
break;
}
case AuthMethod.ServiceToken: {
if (!serviceToken) {
throw new Error("Missing service token for service-token auth");
}
// Service tokens are used directly as Bearer tokens - no login required
infisicalToken = serviceToken;
break;
}
default:
throw new Error(`Invalid authentication method: ${method}`);
}
Expand All @@ -94,6 +104,7 @@ const main = async () => {
envSlug,
infisicalToken,
projectSlug,
projectId,
secretPath,
shouldIncludeImports,
shouldRecurse
Expand Down
26 changes: 18 additions & 8 deletions src/infisical.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export const getRawSecrets = async ({
envSlug,
infisicalToken,
projectSlug,
projectId,
secretPath,
shouldIncludeImports,
shouldRecurse,
Expand All @@ -208,12 +209,28 @@ export const getRawSecrets = async ({
envSlug: string;
infisicalToken: string;
projectSlug: string;
projectId: string;
secretPath: string;
shouldIncludeImports: boolean;
shouldRecurse: boolean;
axiosInstance: AxiosInstance;
}) => {
try {
const params: Record<string, unknown> = {
secretPath,
environment: envSlug,
include_imports: shouldIncludeImports,
recursive: shouldRecurse,
expandSecretReferences: true
};

// Use workspaceId if project-id is provided, otherwise fall back to workspaceSlug
if (projectId) {
params.workspaceId = projectId;
} else {
params.workspaceSlug = projectSlug;
}

const response = await axiosInstance<{
secrets: {
secretKey: string;
Expand All @@ -231,14 +248,7 @@ export const getRawSecrets = async ({
headers: {
Authorization: `Bearer ${infisicalToken}`
},
params: {
secretPath,
environment: envSlug,
include_imports: shouldIncludeImports,
recursive: shouldRecurse,
workspaceSlug: projectSlug,
expandSecretReferences: true
}
params
});

const keyValueSecrets = Object.fromEntries(response.data.secrets.map(secret => [secret.secretKey, secret.secretValue]));
Expand Down