Conjur Store’n’Fetch: 10 minutes to easy secrets management

Part 1: installation and core secrets workflow

 

This is the first blog post in a series focusing on DevOps security workflows with Conjur. Check back for more posts as they are published.

Conjur is a production-ready solution for proactive DevOps security. We talk all the time about how much you’ll like it: in a recent blog post we describe it as “easy” “simple” and “powerful,” and claim you can get productive in “only minutes.” I’m here to show you it’s all that. Follow this walkthrough to get set up with Conjur software and tour some core workflows:

  • Create and use a machine identity
  • Apply a security policy and verify that it is enforced
  • Securely vault and retrieve secrets

This tutorial uses the Conjur command-line interface, but you don’t need to be an expert. All the commands you need to run, and files you need to create, are spelled out in explicit detail.

Preparation

This tutorial has a few prerequisites. They are:

  1. A terminal application. Hyper is a nice one.
  2. The Docker CE package. Visit the Docker website and scroll down to find the download for your operating system.
  3. A Conjur server. Your easiest option is to sign up for an evaluation account from CyberArk. It’s free.When you create an account, you’ll provide an email (which becomes your account name) and you’ll get an API key. Keep these handy for when you need them later.(You can also install your own but here I assume you created an evaluation account.)

Getting Started

Create a project folder and set it as your terminal’s current directory:

cd /path/to/your/folder

Now launch the Conjur CLI container, which has the Conjur CLI and other useful tools pre-installed:

Start a Conjur CLI container

 docker run -it -v ${PWD}:/mnt -w /mnt conjurinc/cli5

Your terminal prompt will change to something like this:

root@c0ef742d884b:/mnt#

That means you’re inside the client container and ready to use the Conjur CLI.

Configuring the client

Now we can configure the Conjur CLI using the account you created and login:

conjur init -u https://eval.conjur.org -a [email protected]
api_key="the-api-key-you-got-from-signing-up"
conjur authn login -u admin -p $api_key

You can check to see that you’re logged in as admin:

whoami

conjur authn whoami

Loading a policy

Right now our Conjur database is empty: apart from the “admin” user and a few other objects that were automatically created for you, we’re at a blank slate.

The next thing to do is to load a security policy, which will create some objects we can use. The purpose of a policy is to model the parts of your applications that have secrets, and the people and machines that need access to those secrets, so that all access can be automatically authorized.

This policy creates a single variable called store-n-fetch/secret and a layer called store-n-fetch. It permits hosts that are members of that layer to fetch, but not update, the secret. In addition, it creates a “host factory” service that allows you to bootstrap machine identity on hosts, automatically adding them into our “store-n-fetch” layer.

According to this policy, only the Conjur admin should be able to update the value of our secret, but all the hosts in our layer should be able to read it. As we go, we’ll test to make sure this is true.

Here’s the policy file we’ll load. Create a file with this text and save it in your project folder as store-n-fetch.yml.

file:store-n-fetch.yml

- !policy
  id: store-n-fetch
  annotations:
    purpose: demonstrate storing & fetching secrets using Conjur
  body:
    - !layer
    - !host_factory
      layers: [ !layer ]
    - !variable secret
    - !permit
      resource: !variable secret
      privilege: [ read, execute ]
      role: !layer

Here’s how to load it into Conjur:

Load a policy

conjur policy load root store-n-fetch.yml

The sub-command policy load root means that we’re loading this policy at the root level (top-most part of the hierarchy) of Conjur. For more complicated workloads, you can create nested policies, but we won’t use that feature yet.

For more about Conjur’s policy format and the philosophy behind it, visit Reference – Policies.

Vault a secret

Now, seeing as we’re logged in as admin, let’s “vault” a secret by storing it in a Conjur variable. Vaulted secrets are automatically secured by [encrypting them with the data key][conjur-encryption].

The command openssl rand creates a random string, which is a good option for a secret to be used by machines.

Add a value to a secret

conjur variable values add store-n-fetch/secret $(openssl rand -hex 16)

Fetch the secret again (as admin)

Having vaulted our secret, let’s fetch it back out again:

Fetch a secret

conjur variable value store-n-fetch/secret

Creating & using a machine identity

You should never let your production machines log in as admin. It’s too much responsibility, and there’s no need! With Conjur you can easily create a machine identity to represent your code and let it authenticate to fetch secrets.

Create a machine identity

Create a hostfactory token

conjur hostfactory tokens create --duration-minutes=5 store-n-fetch | tee token.json
token=$(jq -r .[].token token.json | tr -d '\n\r')
echo "created a host factory token: $token"

We’ve created a time-limited unforgeable token, a pseudo-secret that will allow us to bootstrap new machine identities on our hosts for the next five minutes.

Let’s create a new host and save its data to host.json:

Use hostfactory token to create a host

conjur hostfactory hosts create $token my-host | tee host.json

Now that we’ve created a new host, let’s clean up by revoking our token. (If we didn’t, it would automatically expire after the five minute duration that we set when we created it. But it never hurts to be extra careful.)

Revoke a hostfactory token

conjur hostfactory tokens revoke $token

Authenticate using a machine identity (instead of admin)

Take a look at the data we saved for our new host. It has an ID and an API key, which is all we need to authenticate using the host’s machine identity:

Retrieve the host’s API key

api_key=$(jq -r .api_key host.json | tr -d '\r\n')

Login as host

conjur authn login -u host/my-host -p $api_key

Retrieve a secret using a machine identity

Recall that we permitted the store-n-fetch layer, of which our host is a member, to fetch but not change the value of our secret. Let’s verify that this works as intended:

Fetch a secret just like before

conjur variable value store-n-fetch/secret

So far so good; and when we try to change the secret’s value, we get an error response because the machine identity is not authorized by the policy to do so:

Attempt to modify the secret

conjur variable values add store-n-fetch/secret $(openssl rand -hex 16)

Feedback

I wrote this post to help you understand what Conjur does and how it works. I really care about whether you found it interesting, accessible, and helpful, so if you have any feedback or suggestions, please share. I’m friendly!

Ideas for how to get in touch:

  1. Join the CyberArk Commons and chat with me (I’m @ryan)
  2. Visit Conjur Store’n’Fetch on GitHub and create an issue or pull request
  3. @ me (I’m @ryanprior)