-
Notifications
You must be signed in to change notification settings - Fork 405
Impersonated credentials should implement sign() capability #1443
Description
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: #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 = 'target-serviceaccount@fabled-ray-104117.iam.gserviceaccount.com'
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 #1210
Google Cloud Storage SignedURL with Cloud Run, Cloud Functions and GCE VMs