Update documentation and emit log messages (#85)
This commit is contained in:
parent
d03480e8ad
commit
ac09c292a1
33
README.md
33
README.md
@ -174,6 +174,21 @@ regardless of the authentication mechanism.
|
||||
generate a credentials file which can be used for authentication via gcloud
|
||||
and Google Cloud SDKs in other steps in the workflow. The default is true.
|
||||
|
||||
The credentials file is exported into `$GITHUB_WORKSPACE`, which makes it
|
||||
available to all future steps and filesystems (including Docker-based
|
||||
GitHub Actions). The file is automatically removed at the end of the job
|
||||
via a post action. In order to use exported credentials, you **must** add
|
||||
the `actions/checkout` step before calling `auth`. This is due to how
|
||||
GitHub Actions creates `$GITHUB_WORKSPACE`:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
job_id:
|
||||
steps:
|
||||
- uses: 'actions/checkout@v2' # Must come first!
|
||||
- uses: 'google-github-actions/auth@v0'
|
||||
```
|
||||
|
||||
- `delegates`: (Optional) List of additional service account emails or unique
|
||||
identities to use for impersonation in the chain. By default there are no
|
||||
delegates.
|
||||
@ -419,7 +434,7 @@ the [gcloud][gcloud] command-line tool.
|
||||
--display-name="Demo pool"
|
||||
```
|
||||
|
||||
1. Get the full ID of the Workload Identity Pool:
|
||||
1. Get the full ID of the Workload Identity **Pool**:
|
||||
|
||||
```sh
|
||||
gcloud iam workload-identity-pools describe "my-pool" \
|
||||
@ -435,7 +450,7 @@ the [gcloud][gcloud] command-line tool.
|
||||
```
|
||||
|
||||
|
||||
1. Create a Workload Identity Provider in that pool:
|
||||
1. Create a Workload Identity **Provider** in that pool:
|
||||
|
||||
```sh
|
||||
gcloud iam workload-identity-pools providers create-oidc "my-provider" \
|
||||
@ -470,10 +485,24 @@ the [gcloud][gcloud] command-line tool.
|
||||
export REPO="username/name" # e.g. "google/chrome"
|
||||
|
||||
gcloud iam service-accounts add-iam-policy-binding "my-service-account@${PROJECT_ID}.iam.gserviceaccount.com" \
|
||||
--project="${PROJECT_ID}" \
|
||||
--role="roles/iam.workloadIdentityUser" \
|
||||
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"
|
||||
```
|
||||
|
||||
1. Extract the Workload Identity **Provider** resource name:
|
||||
|
||||
```sh
|
||||
gcloud iam workload-identity-pools providers describe "my-provider" \
|
||||
--project="${PROJECT_ID}"
|
||||
--location="global" \
|
||||
--workload-identity-pool="my-pool" \
|
||||
--format='value(name)'
|
||||
```
|
||||
|
||||
Use this value as the `workload_identity_provider` value in your GitHub
|
||||
Actions YAML.
|
||||
|
||||
1. Use this GitHub Action with the Workload Identity Provider ID and Service
|
||||
Account email. The GitHub Action will mint a GitHub OIDC token and exchange
|
||||
the GitHub token for a Google Cloud access token (assuming the authorization
|
||||
|
2
dist/main/index.js
vendored
2
dist/main/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/post/index.js
vendored
2
dist/post/index.js
vendored
File diff suppressed because one or more lines are too long
29
src/main.ts
29
src/main.ts
@ -1,10 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
debug as logDebug,
|
||||
exportVariable,
|
||||
getBooleanInput,
|
||||
getIDToken,
|
||||
getInput,
|
||||
info as logInfo,
|
||||
setFailed,
|
||||
setOutput,
|
||||
setSecret,
|
||||
@ -13,7 +15,7 @@ import { WorkloadIdentityClient } from './client/workload_identity_client';
|
||||
import { CredentialsJSONClient } from './client/credentials_json_client';
|
||||
import { AuthClient } from './client/auth_client';
|
||||
import { BaseClient } from './base';
|
||||
import { buildDomainWideDelegationJWT, explodeStrings, parseDuration } from './utils';
|
||||
import { buildDomainWideDelegationJWT, errorMessage, explodeStrings, parseDuration } from './utils';
|
||||
|
||||
const secretsWarning =
|
||||
`If you are specifying input values via GitHub secrets, ensure the secret ` +
|
||||
@ -67,6 +69,8 @@ async function run(): Promise<void> {
|
||||
// Instantiate the correct client based on the provided input parameters.
|
||||
let client: AuthClient;
|
||||
if (workloadIdentityProvider) {
|
||||
logDebug(`Using workload identity provider "${workloadIdentityProvider}"`);
|
||||
|
||||
// If we're going to do the OIDC dance, we need to make sure these values
|
||||
// are set. If they aren't, core.getIDToken() will fail and so will
|
||||
// generating the credentials file.
|
||||
@ -87,6 +91,7 @@ async function run(): Promise<void> {
|
||||
oidcTokenRequestURL: oidcTokenRequestURL,
|
||||
});
|
||||
} else {
|
||||
logDebug(`Using credentials JSON`);
|
||||
client = new CredentialsJSONClient({
|
||||
projectID: projectID,
|
||||
credentialsJSON: credentialsJSON,
|
||||
@ -98,6 +103,8 @@ async function run(): Promise<void> {
|
||||
// fails, which means continue-on-error actions will still have the file
|
||||
// available.
|
||||
if (createCredentialsFile) {
|
||||
logDebug(`Creating credentials file`);
|
||||
|
||||
// Note: We explicitly and intentionally export to GITHUB_WORKSPACE
|
||||
// instead of RUNNER_TEMP, because RUNNER_TEMP is not shared with
|
||||
// Docker-based actions on the filesystem. Exporting to GITHUB_WORKSPACE
|
||||
@ -113,14 +120,21 @@ async function run(): Promise<void> {
|
||||
throw new Error('$GITHUB_WORKSPACE is not set');
|
||||
}
|
||||
|
||||
// Create credentials file.
|
||||
const credentialsPath = await client.createCredentialsFile(githubWorkspace);
|
||||
logInfo(`Created credentials file at "${credentialsPath}"`);
|
||||
|
||||
// Output to be available to future steps.
|
||||
setOutput('credentials_file_path', credentialsPath);
|
||||
|
||||
// CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE is picked up by gcloud to use
|
||||
// a specific credential file (subject to change and equivalent to auth/credential_file_override)
|
||||
exportVariable('CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE', credentialsPath);
|
||||
|
||||
// GOOGLE_APPLICATION_CREDENTIALS is used by Application Default Credentials
|
||||
// in all GCP client libraries
|
||||
exportVariable('GOOGLE_APPLICATION_CREDENTIALS', credentialsPath);
|
||||
|
||||
// GOOGLE_GHA_CREDS_PATH is used by other Google GitHub Actions
|
||||
exportVariable('GOOGLE_GHA_CREDS_PATH', credentialsPath);
|
||||
}
|
||||
@ -142,6 +156,8 @@ async function run(): Promise<void> {
|
||||
break;
|
||||
}
|
||||
case 'access_token': {
|
||||
logDebug(`Creating access token`);
|
||||
|
||||
const accessTokenLifetime = parseDuration(getInput('access_token_lifetime'));
|
||||
const accessTokenScopes = explodeStrings(getInput('access_token_scopes'));
|
||||
const accessTokenSubject = getInput('access_token_subject');
|
||||
@ -152,6 +168,12 @@ async function run(): Promise<void> {
|
||||
// Credentials endpoints.
|
||||
let accessToken, expiration;
|
||||
if (accessTokenSubject) {
|
||||
logInfo(
|
||||
`An access token subject was specified, triggering Domain-Wide ` +
|
||||
`Delegation flow. This flow does not support specifying an ` +
|
||||
`access token lifetime of greater than 1 hour.`,
|
||||
);
|
||||
|
||||
const unsignedJWT = buildDomainWideDelegationJWT(
|
||||
serviceAccount,
|
||||
accessTokenSubject,
|
||||
@ -176,6 +198,8 @@ async function run(): Promise<void> {
|
||||
break;
|
||||
}
|
||||
case 'id_token': {
|
||||
logDebug(`Creating id token`);
|
||||
|
||||
const idTokenAudience = getInput('id_token_audience', { required: true });
|
||||
const idTokenIncludeEmail = getBooleanInput('id_token_include_email');
|
||||
const serviceAccount = await client.getServiceAccount();
|
||||
@ -196,7 +220,8 @@ async function run(): Promise<void> {
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
setFailed(`google-github-actions/auth failed with: ${err}`);
|
||||
const msg = errorMessage(err);
|
||||
setFailed(`google-github-actions/auth failed with: ${msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
24
src/utils.ts
24
src/utils.ts
@ -229,3 +229,27 @@ export function buildDomainWideDelegationJWT(
|
||||
|
||||
return JSON.stringify(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* errorMessage extracts the error message from the given error.
|
||||
*
|
||||
* TODO(sethvargo): Candidate for centralization.
|
||||
*
|
||||
*/
|
||||
export function errorMessage(err: unknown): string {
|
||||
if (!err) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let msg = err instanceof Error ? err.message : `${err}`;
|
||||
msg = msg.trim();
|
||||
msg = msg.replace('Error: ', '');
|
||||
msg = msg.trim();
|
||||
|
||||
if (!msg) {
|
||||
return '';
|
||||
}
|
||||
|
||||
msg = msg[0].toLowerCase() + msg.slice(1);
|
||||
return msg;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user