google-auth-library-nodejs
google-auth-library-nodejs copied to clipboard
`Impersonated` credentials should implement `sign()` capability
Impersonated
client does not have any way to generate signedurl or to signbytes.
This credential type uses the IAM api to perform acquire various token types like generateAccessToken
, generateIdToken
(ref: https://github.com/googleapis/google-auth-library-nodejs/issues/1318),
The ability to sign on behalf of the impersonated svc account through the iam api would use the signBlob API.
This feaure request is to surface a sign
interface such that it can be used standalone or though a client such as storage
and allow generation of signedURLs.
Essentially this flow will allow
-
user -> impersonate svc1 --> generate signedurl as svc1
if it helps, I have a sample working below but i had to make some edits
A)
https://github.com/googleapis/google-auth-library-nodejs/blob/main/src/auth/googleauth.ts#L814
async getCredentialsAsync() {
const client = await this.getClient();
if (client instanceof impersonated_1.Impersonated) {
// not really used. Impersonated uses the service accounts email
// it got initialized with
return { client_email: client.targetPrincipal }
}
// ...
// ...
}
B)
https://github.com/googleapis/google-auth-library-nodejs/blob/main/src/auth/googleauth.ts#L946
async sign(data) {
const client = await this.getClient();
if (client instanceof impersonated_1.Impersonated) {
return client.sign(data);
}
// ...
// ...
}
C)
https://github.com/googleapis/google-auth-library-nodejs/blob/main/src/auth/impersonated.ts
/**
* Signs some bytes.
* @param blobToSign Sign bytes.
*/
async sign(blobToSign) {
try {
await this.sourceClient.getAccessToken();
const name = `projects/-/serviceAccounts/${this.targetPrincipal}`;
const u = `${this.endpoint}/v1/${name}:signBlob`;
const body = {
delegates: this.delegates,
payload: Buffer.from(blobToSign).toString('base64')
};
const res = await this.sourceClient.request({
url: u,
data: body,
method: 'POST',
});
const tokenResponse = res.data;
return tokenResponse.signedBlob
}
catch (error) {
}
}
Usage
const { GoogleAuth, Impersonated } = require('google-auth-library');
const { Storage } = require('@google-cloud/storage');
async function main() {
const scopes = 'https://www.googleapis.com/auth/cloud-platform'
// get source credentials
const auth = new GoogleAuth({
scopes: scopes
});
const client = await auth.getClient();
// First impersonate
let targetPrincipal = '[email protected]'
let targetClient = new Impersonated({
sourceClient: client,
targetPrincipal: targetPrincipal,
lifetime: 30,
delegates: [],
targetScopes: [scopes]
});
// test sign
//console.log(await targetClient.sign("foo"));
let projectId = 'fabled-ray-104117'
let bucketName = 'fabled-ray-104117-test'
// use the impersonated creds to bootstrap a storage client
const storageOptions = {
projectId,
authClient: targetClient,
};
const storage = new Storage(storageOptions);
// ####### GCS SignedURL
const signOptions = {
version: 'v4',
action: 'read',
expires: Date.now() + 15 * 60 * 1000, // 15 minutes
};
const su = await storage
.bucket(bucketName)
.file('foo.txt')
.getSignedUrl(signOptions);
console.log(su);
}
main().catch(console.error);
ref https://github.com/googleapis/google-auth-library-nodejs/issues/1210 Google Cloud Storage SignedURL with Cloud Run, Cloud Functions and GCE VMs
@danielbankhead, @FrodoTheTrue, @m0ar