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:
- A terminal application. Hyper is a nice one.
- The Docker CE package. Visit the Docker website and scroll down to find the download for your operating system.
- 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:
- Join the CyberArk Commons and chat with me (I’m
@ryan
) - Visit Conjur Store’n’Fetch on GitHub and create an issue or pull request
- @ me (I’m @ryanprior)
Staff Writer
CyberArk uses a collection of staff writers and practitioners to support the DevOps Security