We have a GCP-based microservice (built within our company) which we are attempting to access via one of our proxies. We set up a service account within GCP which should have access to this resource. We downloaded the credentials file associated with service account (edited for security):
{ "type": "service_account", "project_id": "cluster", "private_key_id": "93158289b2734d823aaeba3b1e4a48a15aaac", "client_email": "apigee-orderservices-dev@ourcluster.iam.gserviceaccount.com", "client_id": "1167082158558367844", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/apigee-orderservices-dev%40ourcluster.iam.gserviceaccount.com", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQE...8K5WjX\n-----END PRIVATE KEY-----\n" }
We are attempting to use a GenerateJWT policy, storing the private_key value in an encrypted kvm so that we can get an authentication token using this JWT request, but I am currently getting "cannot instantiate private key". I'm pretty sure that I'm missing something basic here, but any assistance would be greatly appreciated.
Solved! Go to Solution.
It works for me. I tried 2 different ways.
In either case, the goal was to create a JWT that is signed by an RSA key, obtained from the google service account credentials file. The payload of that JWT should look like this:
{ "iss" : ServiceAccount client_email, "scope" : scope, "aud": ServiceAccount token_uri, "iat": nowInSeconds, "exp": nowInSeconds + (3 * 60) }
In either case, the first thing I did was: create a service account and download the .json file.
Then, Option 1:
Using a text editor, I replaced all \n characters with "newline" . The result looks like this:
-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCsGyx52HRj4z2D oMdmMcdVSU1nbZ6m/r4QOsiFL/KKcdnw6lMkUxwzaIKR27IK1Hngn8SROM5UAp3p WuGwyF2vlIfzOdQXFrjScCT0XJu5wjCjqZe0eUhEWMtBbiKTNSb2K536EG3iy9oY sUZ4RjNvHaRqGn8HAr6mGM5Q8fILIqSYQwNO+htvcso5TKHcR6b79Nz9TcqC6ger WG5pioXNmXSuuMHkTexqbLjdP0MIub/ViiqPIiWkGtv8wAZu+3NuIatuz1VFIq+v ... -----END PRIVATE KEY-----
Added a KVM-Get policy that looks like this:
<KeyValueMapOperations name="KVM-Get-1" mapIdentifier="secrets"> <ExclusiveCache>false</ExclusiveCache> <ExpiryTimeInSecs>300</ExpiryTimeInSecs> <Get assignTo="private.rsakey"> <Key> <Parameter>104855500587360709513</Parameter> </Key> </Get> <Scope>environment</Scope> </KeyValueMapOperations>
You can see I am storing the extracted value to a variable that begins with "private." This is necessary to satisfy the validation for the GenerateJWT policy.
Added a Generate-JWT policy like this
<GenerateJWT name="Generate-JWT-1"> <Algorithm>RS256</Algorithm> <PrivateKey> <Value ref="private.rsakey"/> </PrivateKey> <Issuer>dinoch-trial-171023@appspot.gserviceaccount.com</Issuer> <Audience>https://accounts.google.com/o/oauth2/token</Audience> <ExpiresIn>300s</ExpiresIn> <AdditionalClaims> <Claim name="scope" type="string">https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/datastore</Claim>; </AdditionalClaims> <OutputVariable>output_jwt</OutputVariable> </GenerateJWT>
And that worked. I was able to get an RSA-signed JWT with that policy.
The next thing I tried: rather than manually replacing the \n with newlines, and storing ONLY the private key into the encrypted KVM, I did this:
Stored the entire, unmodified credentials.json file into the encrypted KVM
Extracted that into a context variable with a KVM Get like this:
<KeyValueMapOperations name="KVM-Get-2" mapIdentifier="secrets"> <ExclusiveCache>false</ExclusiveCache> <ExpiryTimeInSecs>300</ExpiryTimeInSecs> <Get assignTo="private.credentialsjson"> <Key> <Parameter>dinoch-trial-171023-bdb91206c515.json</Parameter> </Key> </Get> <Scope>environment</Scope> </KeyValueMapOperations>
Ripped the .json into context variables with a JavaScript policy like this:
<Javascript async="false" continueOnError="false" enabled="true" timeLimit="200" name="JavaScript-1"> <DisplayName>JavaScript-1</DisplayName> <Properties/> <Source> var c = context.getVariable('private.credentialsjson'); c = JSON.parse(c); for (var prop in c) { context.setVariable('private.' + prop, c[prop]); } </Source> </Javascript>
Then generated a JWT with a GenerateJWT policy like this:
<GenerateJWT name="Generate-JWT-2"> <Algorithm>RS256</Algorithm> <PrivateKey> <Value ref="private.private_key"/> </PrivateKey> <Issuer ref="private.client_email"/> <Audience ref="private.token_uri"/> <ExpiresIn>300s</ExpiresIn> <AdditionalClaims> <Claim name="scope" type="string">https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/datastore</Claim>; </AdditionalClaims> <OutputVariable>output_jwt</OutputVariable> </GenerateJWT>
Both ways worked for me. I suspect that it's not working for you because of the \n vs newlines, or some other problem transcribing the private key.