Technical Deep Dive: Using Conjur Secrets in VM-Deployed Ansible Tower Applications

Part Two of the Ansible Tower Technical Deep Dive Series

Secrets management assists organizations in authenticating applications and checking clients before allowing them to access sensitive information, systems, and services. Organizations must transmit sensitive data securely using a secrets management system, like CyberArk Conjur, to alleviate the danger of hackers using checking devices and other techniques to gain access to your sensitive information.

CyberArk Conjur integrates with Ansible Tower, so users and administrators can map sensitive credentials (like passwords, SSH private keys, and the external values of secrets stored) in a secrets management system instead of providing them to Ansible Tower directly.

To learn more about Ansible Tower and how it integrates with Conjur, check out Introduction to Secrets Management in Ansible Tower  and Deploying Conjur Using Ansible Tower .

This article shows you how we can add new secrets to Conjur. Then, we’ll ensure the secrets are only available to a subset of Ansible Tower nodes. We’ll use the conjur_variable plugin to make secrets available to the node. Finally, we’ll finish up by demonstrating a secret in action in a simple Java application (deployed by Ansible Tower).

In addition to VM-deployed Ansible Tower applications, you can also use Conjur secrets in containerized Ansible Tower applications  and Ansible Tower Kubernetes clusters .

Secrets Management in Ansible Tower

Ansible Tower is a web-based application that provides built-in role-based access control. It allows you to scale IT automation, effectively manage complex deployments, and enhance productivity.

Ansible Tower manages secrets in a credential store. The store holds sensitive credential values such as SSH passwords, SSH private keys, API tokens, and other credentials that you must use to:

  • Sign in to a remote host or a remote system.
  • Validate your identity with a cloud endpoint.
  • Pull content from a version control system.

Ansible Tower encrypts the credentials before storing them.

Ansible Tower can access machines and external services on behalf of users and admins using the credentials stored in Ansible Tower. The credentials store scrambles the information you use to sign in to a remote host, confirm a cloud endpoint, or pull content from a control system.

Because access to services usually requires secrets to sign in and use a remote resource, Ansible Tower has an exceptionally secure underlying system. You can integrate the security of this system with CyberArk Conjur using Ansible’s credential plugin.

Adding New Secrets to Conjur

In this section, we are going to learn how to add new secrets to Conjur. First, let’s install Conjur Open Source using Docker to have a working Conjur OSS environment with a Conjur admin account.

As a prerequisite to adding new secrets to Conjur, you must install the Docker toolbox on your machine. Following that, you need to clone the GitHub repository to your working directory by running this command:

git clone https://github.com/cyberark/conjur-quickstart.git

Let’s begin.

Setting up a Conjur OSS Environment

The first step to adding new secrets to Conjur is to set up a Conjur OSS environment on your machine. You should have a working Conjur OSS environment with a Conjur account and an admin user at the end of this.

Defining a Policy

After successfully setting up a Conjur OSS for your environment, let’s go ahead and define a policy. Policies are in YAML files. Policies define entities and the relationships between them. Follow this tutorial to load a policy defining a human and a non-human user representing your application and a secret.

Adding New Secrets to Conjur

Next, let’s review how to add new secrets to Conjur. Recall that while defining a policy in Conjur, we generated the API key for the human user, Dave. We’ll use this API key to authenticate Dave to Conjur. We’ll also use the non-human identity BotApp to authenticate the BotApp application to Conjur.

To add a new secret, we first need to log in as Dave, the human user. Inside your my_app_data file, copy and paste Dave’s API key when prompted for your password like so:

docker-compose exec client conjur authn login -u Dave@BotApp

To confirm that you logged in, run:

docker-compose exec client conjur authn whoami

You should see this message if successful:

{"account":"myConjurAccount","username":"Dave@BotApp"}

The next step is to generate a secret for your application, like so:

secretVal=$(openssl rand -hex 12 | tr -d '\r\n')

Note that this command generates a 12-hex-character value.

The next and final step is storing the generated secret in Conjur. To start, let’s run:

docker-compose exec client conjur variable values add BotApp/secretVar ${secretVal}

This command returns a verification message that reads, “Value added and a predefined policy variable named BotApp/secretVar set with a randomly generated secret.”

Next, let’s see how we can make the secrets available to only a subset of Ansible Tower nodes.

Ensuring Secrets are Only Available to a Subset of Ansible Tower Nodes

In this case, we can use the summon command to make our secrets accessible only to a set of nodes. Note that each Ansible-managed remote node is responsible for using its own identity to retrieve secrets from Conjur.

The summon command provides a port for reading a secrets.yml file, fetching secrets from a secure store, and exporting secret values to a sub-process environment. As a command-line tool, it makes working with secrets easier.

First, configure the Ansible node with a Conjur identity using the Ansible role. Second, install summon and the summon-conjur provider on the Ansible host.

Let’s see how this works:

[Unit]
Description=DemoApp
After=network-online.target

[Service]
User=DemoUser
ExecStart=/usr/local/bin/summon --yaml 'DB_PASSWORD: !var staging/demoapp/database/password' /usr/local/bin/myapp

We use the summon command to retrieve the password stored in Conjur at staging/myapp/database/password. We set it to an env variable named DB_PASSWORD and provided it to the demo application process. The summon command helps keep the secret off disk and retrieves the password anytime the application starts.

Using the conjur_variable Plugin to Make Secrets Available to the Node

We can use the conjur variable plugin to make secrets available to the node. The Conjur variable plugin does this by retrieving credentials from Conjur using the controlling host’s Conjur identity or environment variables. The environment variables could be conjur_account, conjur_cert_file, conjur_authn_login, and so on.

As a prerequisite, the controlling host running Ansible must have a Conjur identity and set parameters on the local controller node:

  • _terms is a variable path that must be a string and is required.
  • as_file is a Boolean parameter that stores lookup results in a temporary file and then returns the file.
  • config_file is a path to the configuration file, which is a YAML file.
  • validate_certs is a flag used to control SSL certificate validation.
  • identity_file is a path to the Conjur identity file, which follows the netrc file format convention.

For example, run the following command:

debug:
          msg: "{{ lookup('cyberark.conjur.conjur_variable', '/path/to/secret') }}"

You should get the following as a return value unique to this lookup:

Key Returned Description
_raw The value stored in Conjur.

The Secrets in Action in a Simple Java Application

In this example, we use a Conjur Java API to integrate Conjur with our project.

First, since we already have the Conjur OSS Server setup, let’s define a variable and give it a secret by running:

docker-compose exec client conjur authn login -u admin -p 
docker-compose exec client conjur variable values add test/secret secretValue

Where our <admin_API_KEY>  is in admin_data.

Second, let’s add Cert to Java Keystore. But first, navigate to your JRE_HOME directory and set it as an env variable, like so:

export JRE_HOME=<path_to_JRE_home>

Let’s also convert the .pem to .der:

openssl x509 -outform der -in conjure-myConjurAccount.pem -out conjur-myConjurAccount.der

It’s now time to add the Cert to Java Keystore.

sudo -E keytool -importcert \
    -alias conjur-myConjurAccount \
    -keystore "$JRE_HOME/lib/security/cacerts" \
    -storepass changeit \
    -file ./conjur-myConjurAccount.der

Third, let’s set our env variables:

export CONJUR_ACCOUNT: myConjurAccount
export CONJUR_AUTHN_LOGIN: host/test/myApp
export CONJUR_AUTHN_API_KEY: <myApp_API_KEY>
export CONJUR_APPLIANCE_URL: https://127.0.0.1:8443
export CONJUR_SECOND_USER: admin
export CONJUR_SECOND_API_KEY: <admin_API_KEY>

It’s now time to set up our Java app. Use either of these steps (the instructions cover both the Maven and JAR file setup) to add the Conjur Java API into your project.

Now, let’s write some code.

import com.cyberark.conjur.api.Conjur;
//import net.conjur.api.Conjur; - for JAR file

public class main {
        static String variableID = "test/secret",
                        originalSecret = "secretValue",
                        newSecret = "ChangedByJavaAPI";
        
        public static void main(String[] args) {        
                String conjurAccount = System.getenv("CONJUR_ACCOUNT");
                String userLogin = System.getenv("CONJUR_AUTHN_LOGIN");
                String userAPIKey = System.getenv("CONJUR_AUTHN_API_KEY");
                String applianceURL = System.getenv("CONJUR_APPLIANCE_URL");
                String secondUser = System.getenv("CONJUR_SECOND_USER");
                String secondUserAPIKey = System.getenv("CONJUR_SECOND_API_KEY");
                
                // Login to user
                System.out.println("Logging into user: "+ userLogin);
                Conjur conjur = new Conjur();
                printLine();
                
                // Get secret as user
                System.out.println("Retrieving secret as: " + userLogin);
                String secret = conjur.variables().retrieveSecret(variableID);
                System.out.println(variableID + ": " + secret);
                printLine();
                
                // Log into account with write privileges
                System.out.println("Logging into user: " + secondUser);
                Conjur adminUser = new Conjur(secondUser, secondUserAPIKey);
                //System.out.println(adminUser.variables().toString());
                
                // Change variable value
                System.out.println("Setting '" + variableID + "' to: " + newSecret);
                adminUser.variables().addSecret(variableID, newSecret);
                printLine();
                
                // Retrieve new value
                System.out.println("Retrieving secret again as: " + userLogin);
                secret = conjur.variables().retrieveSecret(variableID);
                System.out.println(variableID + ": " + secret);
                
                reset(adminUser);
        }
        
        private static void reset(Conjur conjur) {
                conjur.variables().addSecret(variableID, originalSecret);     
        }
        
        private static void printLine() {
                System.out.println("-----------------------");
        }
}

This code retrieves the secret as myApp, logs in a user with write privileges (admin), changes the secret value, and stores the new secret value as myApp.

Conclusion

Ansible is a great tool that can handle the configuration and deployment of applications. However, it’s not a secret management tool. To protect sensitive data, like passwords, you should entrust your confidential data to tools exclusively designed to protect and manage access using an independent secrets management platform like CyberArk Conjur.

CyberArk Conjur plays nicely with Ansible Tower’s built-in secrets management functionality, which helps provide organizations with simple, robotic secrets management integrations. Using Conjur with Ansible Tower can solve many enterprise privilege access problems, such as password resets, storing important auditing information, and least privileged access.

Start securing your secrets and infrastructure by installing Conjur and Ansible Tower today. And, you can check out these documents at any time to learn more information about Conjur and Ansible Tower.