Using API keys securely in your OpenShift microservices and applications
In the microservices landscape, the API provides an essential form of communication between components. To allow secure communication between microservices components, as well as third-party applications, it’s important to be able to consume API keys and other sensitive data in a manner that doesn’t place the data at risk. Secret objects are specifically designed to hold sensitive information, and OpenShift makes exposing this information to the applications that need it easy.
In this post, I’ll demonstrate securely consuming API keys in OpenShift Enterprise 3. We’ll deploy a Sinatra application that uses environment variables to interact with the Twitter API; create a Kubernetes Secret object to store the API keys; expose the secret to the application via environment variables; and then perform a rolling update of the environment variables across our pods.
For this post, I’m assuming you have access to an OpenShift Enterprise deployment. If you don’t have access to OpenShift Enterprise, you can get a local OpenShift 3 deployment with the Red Hat Container Development Kit (CDK)
We’re going to use a pre-built Sinatra application to demonstrate interacting with the Twitter API, and you can find the source code on GitHub. To deploy the app, simply create a new project in your OpenShift project from the GitHub repository:
$ oc new-app https://github.com/jockey10/tripper
Create a route to your application, and list the route in the terminal.
$ oc expose service tripper $ oc get route NAME HOST/PORT PATH SERVICE TERMINATION LABELS tripper <url-to-app> tripper:8080-tcp app=tripper
If you navigate to the application’s URL, you’ll see that it’s up and running. However, any searches return the error “Unable to verify your credentials”, as shown below. Time to grab some API keys!
Grab some API keys
Our application is deployed and running, but it can’t access the Twitter API without any keys. To get a key, navigate to https://apps.twitter.com, and sign in using your Twitter account (create one if required).
Select “Create New App”, and give your new app a name, description, and website. You can use a place-holder such as www.example.com for now if you don’t have a domain name for your app.
Read the Twitter Developer Agreement, select the checkbox, and then select “Create your Twitter Application”.
Once your application has been created you will be redirected to the application management page. Click the “Keys and Access Tokens” tab to view your API keys.
You’ll see two keys listed on this page: the consumer key, which identifies your app to the Twitter API, and the secret, which grants your application access. For now, just leave this page open, and we’ll create a Kubernetes Secret object with this data.
Create the Secret object
We can use a YAML file to create the Secret object that will hold our API keys.
Firstly, we need to encode our Twitter API keys into base64. We can do this easily using Ruby:
$ irb irb(main):001:0> require 'base64' => true irb(main):002:0> Base64.strict_encode64('consumer-key-from-twitter') => "Y29uc3VtZXIta2V5LWZyb20tdHdpdHRlcg==" irb(main):003:0> Base64.strict_encode64('secret-key-from-twitter') => "c2VjcmV0LWtleS1mcm9tLXR3aXR0ZXI="
We can then create a YAML file representing the secret object with these parameters:
#twitter-secrets.yml apiVersion: v1 kind: Secret metadata: name: twitter-secrets type: Opaque data: consumer-key: Y29uc3VtZXIta2V5LWZyb20tdHdpdHRlcg== secret-key: c2VjcmV0LWtleS1mcm9tLXR3aXR0ZXI=
OpenShift objects can be created from a file using the “-f” switch, like so:
$ oc create -f twitter-secrets.yml
To check that the object has been successfully created, you can use the oc command to get a list of Secret objects:
$ oc get secrets builder-dockercfg-anc66 kubernetes.io/dockercfg 1 15d builder-token-2fw2w kubernetes.io/service-account-token 3 15d builder-token-g7o4y kubernetes.io/service-account-token 3 15d default-dockercfg-ni33n kubernetes.io/dockercfg 1 15d default-token-b8hh3 kubernetes.io/service-account-token 3 15d default-token-pwj6b kubernetes.io/service-account-token 3 15d deployer-dockercfg-bb0rp kubernetes.io/dockercfg 1 15d deployer-token-amtd3 kubernetes.io/service-account-token 3 15d deployer-token-uc4o0 kubernetes.io/service-account-token 3 15d twitter-secrets Opaque 2 21h
Consume the Secret object in your application
Our application is expecting the Twitter API consumer and secret keys to be available in environment variables. To deploy the secrets via environment variables, we need to edit the deployment configuration for our application.
Firstly, we need the name of the deployment configuration.
$ oc get dc NAME REVISION REPLICAS TRIGGERED BY tripper 1 1 config,image(tripper:latest)
Now that we have a handle to the deployment configuration, we can edit it:
$ oc edit dc tripper
We can use the following YAML syntax for the environment variables, indicating they are derived from a Secret object:
env: - name: TWITTER_KEY valueFrom: secretKeyRef: name: twitter-secrets key: consumer-key - name: TWITTER_SECRET valueFrom: secretKeyRef: name: twitter-secrets key: secret-key
Simply inject this text into the YAML for the tripper deployment configuration:
apiVersion: v1 kind: DeploymentConfig metadata: . . . spec: . . template: . . spec: . . containers: - env: - name: TWITTER_KEY valueFrom: secretKeyRef: name: twitter-secrets key: consumer-key - name: TWITTER_SECRET valueFrom: secretKeyRef: name: twitter-secrets key: secret-key image: imagePullPolicy: . .
And that’s it! Once you save and exit the deployment configuration file, OpenShift will automatically perform a rolling update of the deployment.
Once the update has been performed, you can navigate back to your application see that it’s now able to interact with the Twitter API.
Thanks for reading!