How to store RSA keys for JWT into KVM? & retrieve them from within API Proxies?

When using the JWT policies in Apigee Edge with RS256 signing, you will probably want to retrieve keys for the policies - either the private key used for signing, or the public key used for verification -from the KeyValueMap in Apigee Edge.

This short article introduces the idea, and gives guidance on how to do it.

First, let's look at the format of public and private keys.

To create your own keys, you can use the openssl utility, which is available on all major platforms. Here's an example of creating a key pair using the newer syntax for openssl:

openssl genpkey  -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -out keypair.pem

The result is a file that looks like this:

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcwfVnEB0PRAVC
qwwPpxKGsEY4pLVIG0CfOSSAu5SyiW7k5UYi69ofHr4M0ujHge93lakdHm0Q3q6X
IhL0mvEwe/AHJKqmbppRvmHFAypBnkMbHh37xsPq2dJEZv1llACS0muVO6wjbrbw
...DRuUzTs6AwW/QFPsYxqD6PgzabxiMa0vQIyhzSXsW9oXEfZZg3TqNfSxa+Gva9yY
ye/hwkFGVdE1h2DtQwyElLa3+L38/64uxnr8yE8lcdVStAjXrPjNUIrL67yHlMMc
dh3Q4Khv8MB+gyp8c5lIjmI5
-----END PRIVATE KEY-----

If you use encryption, FOR NOW, you need to use DES3 encryption, like this:

openssl genpkey -des-ede3-cbc -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -out keypair.pem

regarding the "For Now": For now, the only form of PEM encryption supported by Apigee Edge GenerateJWT policy is DES3. Soon, we expect sometime in March 2019, the policy will support all the various ciphers supported by the openssl tool.

If you want Apigee Edge to use the resulting key (either public or private), then you can load it into the Key-value map. For private keys, probably the encrypted KVM.

In prior generations of the Apigee Edge Administrative UI, it was not possible to load a multi-lined value like the contents of a PEM file, into the KVM. It was always possible to use the Admin API to do this, but the UI was different. As of November 2018, the Apigee Edge administrative user interface has been updated and it now accepts and displays newlines in the textarea very nicely.

8352-screenshot-20190321-114506.png

Even so, most shops are moving toward CI/CD and automating these administrative processes. For that purpose, you need to use the Administrative API. The call is a POST to a URL, that I cannot manage to embed directly into this post, because i-dont-know-why. But wait! if I introduce whitespace, that somehow allows me to proceed. The URL is:

https://api.enterprise.apigee.com/v1/o / ORG / e / ENV /keyvaluemaps / MAP / entries

And if you want to update an existing key in the map:

https://api.enterprise.apigee.com/v1/o / ORG / e / ENV /keyvaluemaps / MAP / entries / KEY

In each case the JSON payload is like this:

{   
   "name" : "key1",
   "value" : "value_one"
}

You can embed this kind of call into any script you use. The call is already wrapped by a couple of libraries: apigee-edge-js (for nodejs), and PSApigeeEdge (for Windows Powershell).

You should do this with each of the public key, and the private key. Probably, you will load the privatekey into an encrypted KVM, and you'll load the public key into a regular KVM. The API calls to create the entry or update the entry are the same.

Once you've loaded the key into the KVM, you then need to use a KVM policy to retrieve the key value at runtime, in the API Proxy. For the Private key, stored in an encrypted KVM, you will need to load the data into a private variable (one with the prefix of private. ) A policy for this looks like so:

<KeyValueMapOperations name='KVM-GetPrivateKey' mapIdentifier='secrets'>
  <Scope>environment</Scope>
  <ExpiryTimeInSecs>15</ExpiryTimeInSecs>
  <Get assignTo='private.privatekey'>
    <Key>
      <Parameter>key1</Parameter>
    </Key>
  </Get>
</KeyValueMapOperations>

And for the public key, maybe something like this:

<KeyValueMapOperations name='KVM-GetPublicKey' mapIdentifier='non-secrets'>
  <Scope>environment</Scope>
  <ExpiryTimeInSecs>15</ExpiryTimeInSecs>
  <Get assignTo='publickey'>
    <Key>
      <Parameter>key1</Parameter>
    </Key>
  </Get>
</KeyValueMapOperations>

And then reference those variables as you would normally, according to the JWT policy documentation. For signing:

<GenerateJWT name="Generate-JWT-RS256-Example">
    <Algorithm>RS256</Algorithm>
    <PrivateKey>
        <Value ref="private.privatekey"/>
        <Id>unique-identifier-for-privatekey-here</Id>
    </PrivateKey>
    ...
</GenerateJWT>

And for verifying,

<VerifyJWT name="Verify-JWT-RS256">
    <Algorithm>RS256</Algorithm>
    <Source>inbound.jwt</Source>
    <PublicKey>
        <Value ref='publickey'/>
    </PublicKey>
    ...
</VerifyJWT>

I have updated the proxies in the JWT-demo repository to demonstrate this capability. Check the readme there for more information. There is even a loadPemIntoKVM.js script that will work for your org and environment.

Comments
teerakiatchi
Bronze 2
Bronze 2
regarding the "For Now": For now, the only form of PEM encryption supported by Apigee Edge GenerateJWT policy is DES3. Soon, we expect sometime in June 2018, the policy will support all the various ciphers supported by the openssl tool.

As of Now: Aug2018, is the other PEM encryption supported by Apigee GenerateJWT policy possible now? @Dino-at-Google

dchiesa1
Staff

Ah, thanks for the question.

The scheduled June 2018 release did not actually happen, so this minor feature did not make it into the public cloud. We currently expect to release this function towards the end of August.

At least until then, your encrypted key must still use DES3.

EDIT = This change is scheduled to be released in March 2019.

Version history
Last update:
‎06-04-2018 04:12 PM
Updated by: