Refactor to support access and id tokens (#3)
This commit is contained in:
parent
afef6a5b6d
commit
cb396c3f31
62
.github/workflows/test.yaml
vendored
62
.github/workflows/test.yaml
vendored
@ -9,13 +9,34 @@ on:
|
|||||||
- 'main'
|
- 'main'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run:
|
unit:
|
||||||
name: 'test'
|
name: 'unit'
|
||||||
|
runs-on: 'ubuntu-latest'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: 'actions/checkout@v2'
|
||||||
|
|
||||||
|
- uses: 'actions/setup-node@master'
|
||||||
|
with:
|
||||||
|
node-version: '12.x'
|
||||||
|
|
||||||
|
- name: 'npm install'
|
||||||
|
run: 'npm install'
|
||||||
|
|
||||||
|
- name: 'npm lint'
|
||||||
|
run: 'npm run lint'
|
||||||
|
|
||||||
|
- name: 'npm test'
|
||||||
|
run: 'npm run test'
|
||||||
|
|
||||||
|
access_token:
|
||||||
|
name: 'access_token'
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write
|
id-token: write
|
||||||
contents: read
|
contents: read
|
||||||
runs-on: '${{ matrix.operating-system }}'
|
runs-on: '${{ matrix.operating-system }}'
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
operating-system:
|
operating-system:
|
||||||
- 'ubuntu-latest'
|
- 'ubuntu-latest'
|
||||||
@ -28,19 +49,40 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: '12.x'
|
node-version: '12.x'
|
||||||
|
|
||||||
- id: 'integration'
|
- id: 'access-token'
|
||||||
name: 'integration'
|
name: 'integration'
|
||||||
uses: './'
|
uses: './'
|
||||||
with:
|
with:
|
||||||
|
token_format: 'access_token'
|
||||||
workload_identity_provider: 'projects/469401941463/locations/global/workloadIdentityPools/github-actions/providers/github-oidc-auth-google-cloud'
|
workload_identity_provider: 'projects/469401941463/locations/global/workloadIdentityPools/github-actions/providers/github-oidc-auth-google-cloud'
|
||||||
service_account: 'github-secret-accessor@actions-oidc-test.iam.gserviceaccount.com'
|
service_account: 'github-secret-accessor@actions-oidc-test.iam.gserviceaccount.com'
|
||||||
id_token_audience: 'foo'
|
|
||||||
|
|
||||||
- name: 'npm install'
|
id_token:
|
||||||
run: 'npm install'
|
name: 'id_token'
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: read
|
||||||
|
runs-on: '${{ matrix.operating-system }}'
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
operating-system:
|
||||||
|
- 'ubuntu-latest'
|
||||||
|
- 'windows-latest'
|
||||||
|
- 'macos-latest'
|
||||||
|
steps:
|
||||||
|
- uses: 'actions/checkout@v2'
|
||||||
|
|
||||||
- name: 'npm lint'
|
- uses: 'actions/setup-node@master'
|
||||||
run: 'npm run lint'
|
with:
|
||||||
|
node-version: '12.x'
|
||||||
|
|
||||||
- name: 'npm test'
|
- id: 'id-token'
|
||||||
run: 'npm run test'
|
name: 'integration'
|
||||||
|
uses: './'
|
||||||
|
with:
|
||||||
|
token_format: 'id_token'
|
||||||
|
workload_identity_provider: 'projects/469401941463/locations/global/workloadIdentityPools/github-actions/providers/github-oidc-auth-google-cloud'
|
||||||
|
service_account: 'github-secret-accessor@actions-oidc-test.iam.gserviceaccount.com'
|
||||||
|
id_token_audience: 'my-aud'
|
||||||
|
id_token_include_email: true
|
||||||
|
28
README.md
28
README.md
@ -41,6 +41,7 @@ jobs:
|
|||||||
name: 'Authenticate to Google Cloud'
|
name: 'Authenticate to Google Cloud'
|
||||||
uses: 'github.com/sethvargo/oidc-auth-google-cloud'
|
uses: 'github.com/sethvargo/oidc-auth-google-cloud'
|
||||||
with:
|
with:
|
||||||
|
token_format: 'access_token'
|
||||||
workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider'
|
workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider'
|
||||||
service_account: 'my-service-account@my-project.iam.gserviceaccount.com'
|
service_account: 'my-service-account@my-project.iam.gserviceaccount.com'
|
||||||
|
|
||||||
@ -74,23 +75,40 @@ jobs:
|
|||||||
`"sigstore"`, but this variable exists in case custom values are permitted
|
`"sigstore"`, but this variable exists in case custom values are permitted
|
||||||
in the future. The default value is `"sigstore"`.
|
in the future. The default value is `"sigstore"`.
|
||||||
|
|
||||||
|
- `token_format`: (Optional) Format of the generated token. For OAuth 2.0
|
||||||
|
access tokens, specify "access_token". For OIDC tokens, specify "id_token".
|
||||||
|
The default value is "access_token".
|
||||||
|
|
||||||
- `delegates`: (Optional) List of additional service account emails or unique
|
- `delegates`: (Optional) List of additional service account emails or unique
|
||||||
identities to use for impersonation in the chain. By default there are no
|
identities to use for impersonation in the chain. By default there are no
|
||||||
delegates.
|
delegates.
|
||||||
|
|
||||||
- `lifetime`: (Optional) Desired lifetime duration of the access token, in
|
- `access_token_lifetime`: (Optional) Desired lifetime duration of the access
|
||||||
seconds. This must be specified as the number of seconds with a trailing "s"
|
token, in seconds. This must be specified as the number of seconds with a
|
||||||
(e.g. 30s). The default value is 1 hour (3600s).
|
trailing "s" (e.g. 30s). The default value is 1 hour (3600s).
|
||||||
|
|
||||||
|
- `access_token_scopes`: (Optional) List of OAuth 2.0 access scopes to be
|
||||||
|
included in the generated token. This is only valid when "token_format" is
|
||||||
|
"access_token". The default value is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://www.googleapis.com/auth/cloud-platform
|
||||||
|
```
|
||||||
|
|
||||||
- `id_token_audience`: (Optional) The audience for the generated ID Token.
|
- `id_token_audience`: (Optional) The audience for the generated ID Token.
|
||||||
|
|
||||||
|
- `id_token_include_email`: (Optional) Optional parameter of whether to
|
||||||
|
include the service account email in the generated token. If true, the token
|
||||||
|
will contain "email" and "email_verified" claims. This is only valid when
|
||||||
|
"token_format" is "access_token". The default value is false.
|
||||||
|
|
||||||
## Outputs
|
## Outputs
|
||||||
|
|
||||||
- `access_token`: The authenticated Google Cloud access token for calling
|
- `access_token`: The authenticated Google Cloud access token for calling
|
||||||
other Google Cloud APIs.
|
other Google Cloud APIs.
|
||||||
|
|
||||||
- `expiration`: The RFC3339 UTC "Zulu" format timestamp when the token
|
- `access_token_expiration`: The RFC3339 UTC "Zulu" format timestamp when the
|
||||||
expires.
|
token expires.
|
||||||
|
|
||||||
- `id_token`: The authenticated Google Cloud ID token. This token is only
|
- `id_token`: The authenticated Google Cloud ID token. This token is only
|
||||||
generated when `id_token_audience` input parameter is provided.
|
generated when `id_token_audience` input parameter is provided.
|
||||||
|
47
action.yml
47
action.yml
@ -15,8 +15,8 @@
|
|||||||
name: 'OIDC Authenticate to Google Cloud'
|
name: 'OIDC Authenticate to Google Cloud'
|
||||||
author: 'sethvargo'
|
author: 'sethvargo'
|
||||||
description: |-
|
description: |-
|
||||||
Authenticate to Google Cloud from GitHub Actions using an OIDC token and
|
Generate credentials to authenticate to Google Cloud from GitHub Actions using
|
||||||
Workload Identity Federation.
|
an OIDC token and Workload Identity Federation.
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
workload_identity_provider:
|
workload_identity_provider:
|
||||||
@ -38,35 +38,62 @@ inputs:
|
|||||||
exists in case custom values are permitted in the future.
|
exists in case custom values are permitted in the future.
|
||||||
default: 'sigstore'
|
default: 'sigstore'
|
||||||
required: false
|
required: false
|
||||||
|
token_format:
|
||||||
|
description: |-
|
||||||
|
Format for the generated token. For OAuth 2.0 access tokens, specify
|
||||||
|
"access_token". For OIDC tokens, specify "id_token".
|
||||||
|
default: 'access_token'
|
||||||
|
required: true
|
||||||
delegates:
|
delegates:
|
||||||
description: |-
|
description: |-
|
||||||
List of additional service account emails or unique identities to use for
|
List of additional service account emails or unique identities to use for
|
||||||
impersonation in the chain.
|
impersonation in the chain.
|
||||||
default: ''
|
default: ''
|
||||||
required: false
|
required: false
|
||||||
lifetime:
|
|
||||||
|
# access token params
|
||||||
|
access_token_lifetime:
|
||||||
description: |-
|
description: |-
|
||||||
Desired lifetime duration of the access token, in seconds. This must be
|
Desired lifetime duration of the access token, in seconds. This must be
|
||||||
specified as the number of seconds with a trailing "s" (e.g. 30s).
|
specified as the number of seconds with a trailing "s" (e.g. 30s). This is
|
||||||
|
only valid when "token_format" is "access_token".
|
||||||
default: '3600s'
|
default: '3600s'
|
||||||
required: false
|
required: false
|
||||||
|
access_token_scopes:
|
||||||
|
description: |-
|
||||||
|
List of OAuth 2.0 access scopes to be included in the generated token.
|
||||||
|
This is only valid when "token_format" is "access_token".
|
||||||
|
default: 'https://www.googleapis.com/auth/cloud-platform'
|
||||||
|
|
||||||
|
# id token params
|
||||||
id_token_audience:
|
id_token_audience:
|
||||||
description: |-
|
description: |-
|
||||||
The audience for the generated Google Cloud ID Token.
|
The audience (aud) for the generated Google Cloud ID Token. This is only
|
||||||
|
valid when "token_format" is "id_token".
|
||||||
default: ''
|
default: ''
|
||||||
required: false
|
required: false
|
||||||
|
id_token_include_email:
|
||||||
|
description: |-
|
||||||
|
Optional parameter of whether to include the service account email in the
|
||||||
|
generated token. If true, the token will contain "email" and
|
||||||
|
"email_verified" claims. This is only valid when "token_format" is
|
||||||
|
"access_token".
|
||||||
|
default: false
|
||||||
|
required: false
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
access_token:
|
access_token:
|
||||||
description: |-
|
description: |-
|
||||||
The Google Cloud access token for calling other Google Cloud APIs.
|
The Google Cloud access token for calling other Google Cloud APIs. This
|
||||||
expiration:
|
is only available when "token_format" is "access_token".
|
||||||
|
access_token_expiration:
|
||||||
description: |-
|
description: |-
|
||||||
The expiration timestamp for the access token.
|
The expiration timestamp for the access token. This is only available
|
||||||
|
when "token_format" is "access_token".
|
||||||
id_token:
|
id_token:
|
||||||
description: |-
|
description: |-
|
||||||
The Google Cloud ID token. This token is only generated when
|
The Google Cloud ID token. This is only available when "token_format" is
|
||||||
`id_token_audience` input parameter was provided.
|
"id_token".
|
||||||
|
|
||||||
branding:
|
branding:
|
||||||
icon: 'lock'
|
icon: 'lock'
|
||||||
|
66
dist/index.js
vendored
66
dist/index.js
vendored
@ -225,37 +225,51 @@ function run() {
|
|||||||
});
|
});
|
||||||
const serviceAccount = core.getInput('service_account', { required: true });
|
const serviceAccount = core.getInput('service_account', { required: true });
|
||||||
const audience = core.getInput('audience');
|
const audience = core.getInput('audience');
|
||||||
|
const tokenFormat = core.getInput('token_format', { required: true });
|
||||||
const delegates = explodeStrings(core.getInput('delegates'));
|
const delegates = explodeStrings(core.getInput('delegates'));
|
||||||
const lifetime = core.getInput('lifetime');
|
const accessTokenLifetime = core.getInput('access_token_lifetime');
|
||||||
|
const accessTokenScopes = explodeStrings(core.getInput('access_token_scopes'));
|
||||||
const idTokenAudience = core.getInput('id_token_audience');
|
const idTokenAudience = core.getInput('id_token_audience');
|
||||||
|
const idTokenIncludeEmail = core.getBooleanInput('id_token_include_email');
|
||||||
|
// Get the GitHub OIDC token.
|
||||||
const githubOIDCToken = yield core.getIDToken(audience);
|
const githubOIDCToken = yield core.getIDToken(audience);
|
||||||
|
|
||||||
// Exchange the GitHub OIDC token for a Google Federated Token.
|
// Exchange the GitHub OIDC token for a Google Federated Token.
|
||||||
const googleFederatedToken = yield client_1.Client.googleFederatedToken({
|
const googleFederatedToken = yield client_1.Client.googleFederatedToken({
|
||||||
providerID: workloadIdentityProvider,
|
providerID: workloadIdentityProvider,
|
||||||
token: githubOIDCToken,
|
token: githubOIDCToken,
|
||||||
});
|
});
|
||||||
core.setSecret(googleFederatedToken);
|
core.setSecret(googleFederatedToken);
|
||||||
// Exchange the Google Federated Token for an access token.
|
switch (tokenFormat) {
|
||||||
const { accessToken, expiration } = yield client_1.Client.googleAccessToken({
|
case 'access_token': {
|
||||||
token: googleFederatedToken,
|
// Exchange the Google Federated Token for an access token.
|
||||||
serviceAccount: serviceAccount,
|
const { accessToken, expiration } = yield client_1.Client.googleAccessToken({
|
||||||
delegates: delegates,
|
token: googleFederatedToken,
|
||||||
lifetime: lifetime,
|
serviceAccount: serviceAccount,
|
||||||
});
|
delegates: delegates,
|
||||||
core.setSecret(accessToken);
|
lifetime: accessTokenLifetime,
|
||||||
core.setOutput('access_token', accessToken);
|
scopes: accessTokenScopes,
|
||||||
core.setOutput('expiration', expiration);
|
});
|
||||||
// Exchange the Google Federated Token for an ID token.
|
core.setSecret(accessToken);
|
||||||
if (idTokenAudience != '') {
|
core.setOutput('access_token', accessToken);
|
||||||
const { token } = yield client_1.Client.googleIDToken({
|
core.setOutput('access_token_expiration', expiration);
|
||||||
token: googleFederatedToken,
|
break;
|
||||||
serviceAccount: serviceAccount,
|
}
|
||||||
delegates: delegates,
|
case 'id_token': {
|
||||||
audience: idTokenAudience,
|
// Exchange the Google Federated Token for an id token.
|
||||||
});
|
const { token } = yield client_1.Client.googleIDToken({
|
||||||
core.setSecret(token);
|
token: googleFederatedToken,
|
||||||
core.setOutput('id_token', token);
|
serviceAccount: serviceAccount,
|
||||||
|
delegates: delegates,
|
||||||
|
audience: idTokenAudience,
|
||||||
|
includeEmail: idTokenIncludeEmail,
|
||||||
|
});
|
||||||
|
core.setSecret(token);
|
||||||
|
core.setOutput('id_token', token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new Error(`unknown token format "${tokenFormat}"`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
@ -1880,14 +1894,14 @@ class Client {
|
|||||||
* googleAccessToken generates a Google Cloud access token for the provided
|
* googleAccessToken generates a Google Cloud access token for the provided
|
||||||
* service account email or unique id.
|
* service account email or unique id.
|
||||||
*/
|
*/
|
||||||
static googleAccessToken({ token, serviceAccount, delegates, lifetime, }) {
|
static googleAccessToken({ token, serviceAccount, delegates, scopes, lifetime, }) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const serviceAccountID = `projects/-/serviceAccounts/${serviceAccount}`;
|
const serviceAccountID = `projects/-/serviceAccounts/${serviceAccount}`;
|
||||||
const tokenURL = new url_1.URL(`https://iamcredentials.googleapis.com/v1/${serviceAccountID}:generateAccessToken`);
|
const tokenURL = new url_1.URL(`https://iamcredentials.googleapis.com/v1/${serviceAccountID}:generateAccessToken`);
|
||||||
const data = {
|
const data = {
|
||||||
delegates: delegates,
|
delegates: delegates,
|
||||||
scope: 'https://www.googleapis.com/auth/cloud-platform',
|
|
||||||
lifetime: lifetime,
|
lifetime: lifetime,
|
||||||
|
scope: scopes,
|
||||||
};
|
};
|
||||||
const opts = {
|
const opts = {
|
||||||
hostname: tokenURL.hostname,
|
hostname: tokenURL.hostname,
|
||||||
@ -1917,14 +1931,14 @@ class Client {
|
|||||||
* googleIDToken generates a Google Cloud ID token for the provided
|
* googleIDToken generates a Google Cloud ID token for the provided
|
||||||
* service account email or unique id.
|
* service account email or unique id.
|
||||||
*/
|
*/
|
||||||
static googleIDToken({ token, serviceAccount, audience, delegates, }) {
|
static googleIDToken({ token, serviceAccount, audience, delegates, includeEmail, }) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const serviceAccountID = `projects/-/serviceAccounts/${serviceAccount}`;
|
const serviceAccountID = `projects/-/serviceAccounts/${serviceAccount}`;
|
||||||
const tokenURL = new url_1.URL(`https://iamcredentials.googleapis.com/v1/${serviceAccountID}:generateIdToken`);
|
const tokenURL = new url_1.URL(`https://iamcredentials.googleapis.com/v1/${serviceAccountID}:generateIdToken`);
|
||||||
const data = {
|
const data = {
|
||||||
delegates: delegates,
|
delegates: delegates,
|
||||||
audience: audience,
|
audience: audience,
|
||||||
includeEmail: true,
|
includeEmail: includeEmail,
|
||||||
};
|
};
|
||||||
const opts = {
|
const opts = {
|
||||||
hostname: tokenURL.hostname,
|
hostname: tokenURL.hostname,
|
||||||
|
36
package-lock.json
generated
36
package-lock.json
generated
@ -55,9 +55,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.14.9",
|
"version": "7.15.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
|
||||||
"integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==",
|
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@ -287,9 +287,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "16.9.1",
|
"version": "16.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.2.tgz",
|
||||||
"integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==",
|
"integrity": "sha512-ZHty/hKoOLZvSz6BtP1g7tc7nUeJhoCf3flLjh8ZEv1vFKBWHXcnMbJMyN/pftSljNyy0kNW/UqI3DccnBnZ8w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
@ -1975,9 +1975,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
|
||||||
"integrity": "sha512-DsEPLY1dE5HF3BxCRBmD4uYZ+5DCbvatnolqTqcxEgKVZnL2kUfyu7b8pPQ5+hTBkdhU9SLUmK0/pHb07RE4WQ==",
|
"integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin-prettier.js"
|
"prettier": "bin-prettier.js"
|
||||||
@ -2714,9 +2714,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helper-validator-identifier": {
|
"@babel/helper-validator-identifier": {
|
||||||
"version": "7.14.9",
|
"version": "7.15.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
|
||||||
"integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==",
|
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@babel/highlight": {
|
"@babel/highlight": {
|
||||||
@ -2906,9 +2906,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "16.9.1",
|
"version": "16.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.2.tgz",
|
||||||
"integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==",
|
"integrity": "sha512-ZHty/hKoOLZvSz6BtP1g7tc7nUeJhoCf3flLjh8ZEv1vFKBWHXcnMbJMyN/pftSljNyy0kNW/UqI3DccnBnZ8w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@typescript-eslint/eslint-plugin": {
|
"@typescript-eslint/eslint-plugin": {
|
||||||
@ -4115,9 +4115,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
|
||||||
"integrity": "sha512-DsEPLY1dE5HF3BxCRBmD4uYZ+5DCbvatnolqTqcxEgKVZnL2kUfyu7b8pPQ5+hTBkdhU9SLUmK0/pHb07RE4WQ==",
|
"integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"prettier-linter-helpers": {
|
"prettier-linter-helpers": {
|
||||||
|
@ -34,6 +34,7 @@ interface GoogleAccessTokenParameters {
|
|||||||
token: string;
|
token: string;
|
||||||
serviceAccount: string;
|
serviceAccount: string;
|
||||||
delegates?: Array<string>;
|
delegates?: Array<string>;
|
||||||
|
scopes?: Array<string>;
|
||||||
lifetime?: string;
|
lifetime?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +69,7 @@ interface GoogleIDTokenParameters {
|
|||||||
serviceAccount: string;
|
serviceAccount: string;
|
||||||
audience: string;
|
audience: string;
|
||||||
delegates?: Array<string>;
|
delegates?: Array<string>;
|
||||||
|
includeEmail?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,6 +165,7 @@ export class Client {
|
|||||||
token,
|
token,
|
||||||
serviceAccount,
|
serviceAccount,
|
||||||
delegates,
|
delegates,
|
||||||
|
scopes,
|
||||||
lifetime,
|
lifetime,
|
||||||
}: GoogleAccessTokenParameters): Promise<GoogleAccessTokenResponse> {
|
}: GoogleAccessTokenParameters): Promise<GoogleAccessTokenResponse> {
|
||||||
const serviceAccountID = `projects/-/serviceAccounts/${serviceAccount}`;
|
const serviceAccountID = `projects/-/serviceAccounts/${serviceAccount}`;
|
||||||
@ -172,8 +175,8 @@ export class Client {
|
|||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
delegates: delegates,
|
delegates: delegates,
|
||||||
scope: 'https://www.googleapis.com/auth/cloud-platform',
|
|
||||||
lifetime: lifetime,
|
lifetime: lifetime,
|
||||||
|
scope: scopes,
|
||||||
};
|
};
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
@ -209,6 +212,7 @@ export class Client {
|
|||||||
serviceAccount,
|
serviceAccount,
|
||||||
audience,
|
audience,
|
||||||
delegates,
|
delegates,
|
||||||
|
includeEmail,
|
||||||
}: GoogleIDTokenParameters): Promise<GoogleIDTokenResponse> {
|
}: GoogleIDTokenParameters): Promise<GoogleIDTokenResponse> {
|
||||||
const serviceAccountID = `projects/-/serviceAccounts/${serviceAccount}`;
|
const serviceAccountID = `projects/-/serviceAccounts/${serviceAccount}`;
|
||||||
const tokenURL = new URL(
|
const tokenURL = new URL(
|
||||||
@ -218,7 +222,7 @@ export class Client {
|
|||||||
const data = {
|
const data = {
|
||||||
delegates: delegates,
|
delegates: delegates,
|
||||||
audience: audience,
|
audience: audience,
|
||||||
includeEmail: true,
|
includeEmail: includeEmail,
|
||||||
};
|
};
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
|
58
src/main.ts
58
src/main.ts
@ -35,10 +35,14 @@ async function run(): Promise<void> {
|
|||||||
});
|
});
|
||||||
const serviceAccount = core.getInput('service_account', { required: true });
|
const serviceAccount = core.getInput('service_account', { required: true });
|
||||||
const audience = core.getInput('audience');
|
const audience = core.getInput('audience');
|
||||||
|
const tokenFormat = core.getInput('token_format', { required: true });
|
||||||
const delegates = explodeStrings(core.getInput('delegates'));
|
const delegates = explodeStrings(core.getInput('delegates'));
|
||||||
const lifetime = core.getInput('lifetime');
|
const accessTokenLifetime = core.getInput('access_token_lifetime');
|
||||||
|
const accessTokenScopes = explodeStrings(core.getInput('access_token_scopes'));
|
||||||
const idTokenAudience = core.getInput('id_token_audience');
|
const idTokenAudience = core.getInput('id_token_audience');
|
||||||
|
const idTokenIncludeEmail = core.getBooleanInput('id_token_include_email');
|
||||||
|
|
||||||
|
// Get the GitHub OIDC token.
|
||||||
const githubOIDCToken = await core.getIDToken(audience);
|
const githubOIDCToken = await core.getIDToken(audience);
|
||||||
|
|
||||||
// Exchange the GitHub OIDC token for a Google Federated Token.
|
// Exchange the GitHub OIDC token for a Google Federated Token.
|
||||||
@ -48,27 +52,37 @@ async function run(): Promise<void> {
|
|||||||
});
|
});
|
||||||
core.setSecret(googleFederatedToken);
|
core.setSecret(googleFederatedToken);
|
||||||
|
|
||||||
// Exchange the Google Federated Token for an access token.
|
switch (tokenFormat) {
|
||||||
const { accessToken, expiration } = await Client.googleAccessToken({
|
case 'access_token': {
|
||||||
token: googleFederatedToken,
|
// Exchange the Google Federated Token for an access token.
|
||||||
serviceAccount: serviceAccount,
|
const { accessToken, expiration } = await Client.googleAccessToken({
|
||||||
delegates: delegates,
|
token: googleFederatedToken,
|
||||||
lifetime: lifetime,
|
serviceAccount: serviceAccount,
|
||||||
});
|
delegates: delegates,
|
||||||
core.setSecret(accessToken);
|
lifetime: accessTokenLifetime,
|
||||||
core.setOutput('access_token', accessToken);
|
scopes: accessTokenScopes,
|
||||||
core.setOutput('expiration', expiration);
|
});
|
||||||
|
core.setSecret(accessToken);
|
||||||
// Exchange the Google Federated Token for an ID token.
|
core.setOutput('access_token', accessToken);
|
||||||
if (idTokenAudience != '') {
|
core.setOutput('access_token_expiration', expiration);
|
||||||
const { token } = await Client.googleIDToken({
|
break;
|
||||||
token: googleFederatedToken,
|
}
|
||||||
serviceAccount: serviceAccount,
|
case 'id_token': {
|
||||||
delegates: delegates,
|
// Exchange the Google Federated Token for an id token.
|
||||||
audience: idTokenAudience,
|
const { token } = await Client.googleIDToken({
|
||||||
});
|
token: googleFederatedToken,
|
||||||
core.setSecret(token);
|
serviceAccount: serviceAccount,
|
||||||
core.setOutput('id_token', token);
|
delegates: delegates,
|
||||||
|
audience: idTokenAudience,
|
||||||
|
includeEmail: idTokenIncludeEmail,
|
||||||
|
});
|
||||||
|
core.setSecret(token);
|
||||||
|
core.setOutput('id_token', token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new Error(`unknown token format "${tokenFormat}"`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.setFailed(`Action failed with error: ${err}`);
|
core.setFailed(`Action failed with error: ${err}`);
|
||||||
|
Loading…
Reference in New Issue
Block a user