Running a Job - the easy way with gostint-client

gostint-client

Sister project gostint-client provides a CLI (and eventually an api library) to simplify securely submitting jobs to DevOps automation tools running from the gostint API.

The latest release is available from the github Releases page.

Usage

$ ./gostint-client -h
Usage of ./gostint-client:
  -cont-on-warnings
    	Continue to run job even if vault reported warnings when looking up secret refs, overrides value in job-json
  -content string
    	Folder or targz to inject into the container relative to root '/' folder, overrides value in job-json
  -debug
    	Enable debugging
  -entrypoint string
    	JSON array of string parts defining the container's entrypoint, e.g.: '["ansible"]', overrides value in job-json
  -env-vars string
    	JSON array of strings providing envronment variables to be passed to the job container, e.g.: '["MYVAR=value"]'
  -gostint-approle string
    	Vault App Role Name of GoStint to run job on (can read file e.g. '@gostint_role.txt') (default "gostint-role")
  -image string
    	Docker image to run job within, overrides value in job-json
  -image-pull-policy string
    	Docker image pull policy: IfNotPresent or Always (default "IfNotPresent")
  -job-json string
    	JSON Job request
  -poll-interval int
    	Overide default poll interval for results (in seconds) (default 1)
  -qname string
    	Job Queue to submit to, overrides value in job-json
  -run string
    	JSON array of string parts defining the command to run in the container - aka the job, e.g.: '["-m", "ping", "127.0.0.1"]', overrides value in job-json
  -run-dir string
    	Working directory within the container to run the job
  -secret-filetype string
    	Injected secret file type, can be either 'yaml' (default) or 'json', overrides value in job-json (default "yaml")
  -secret-refs string
    	JSON array of strings providing paths to secrets in the Vault to be injected into the job's container, e.g.: '["mysecret@secret/data/my-secret.my-value", ...]', overrides value in job-json
  -url string
    	GoStint API URL, e.g. https://somewhere:3232
  -vault-roleid string
    	Requestor's Vault App Role ID (can read file e.g. '@role_id.txt')
  -vault-secretid string
    	Requestor's Vault App Secret ID (can read file e.g. '@secret_id.txt')
  -vault-token string
    	Requestor's Vault token - used instead of App Role (can read file e.g. '@token.txt')
  -vault-url string
    	Vault API URL, e.g. https://your-vault:8200 - defaults to env var VAULT_ADDR
  -wait
    	Wait for job to complete before returning final status (default true)

Debugging with -debug option

$ gostint-client -vault-token=@.vault_token \
  -url=https://127.0.0.1:13232 \
  -vault-url=http://127.0.0.1:18200 \
  -image=alpine \
  -run='["cat", "/etc/os-release"]' \
  -debug

2018-08-28T13:11:23+01:00 Validating command line arguments
2018-08-28T13:11:23+01:00 Resolving file argument @.vault_token
2018-08-28T13:11:23+01:00 Building Job Request
2018-08-28T13:11:23+01:00 Getting Vault api connection http://127.0.0.1:18200
2018-08-28T13:11:23+01:00 Authenticating with Vault
2018-08-28T13:11:23+01:00 Getting minimal token to authenticate with GoStint API
2018-08-28T13:11:24+01:00 Getting Wrapped Secret_ID for the AppRole
2018-08-28T13:11:24+01:00 Encrypting the job payload
2018-08-28T13:11:24+01:00 Getting minimal limited use / ttl token for the cubbyhole
2018-08-28T13:11:24+01:00 Putting encrypted payload in a vault cubbyhole
2018-08-28T13:11:24+01:00 Creating job request wrapper to submit
2018-08-28T13:11:24+01:00 Submitting job
2018-08-28T13:11:24+01:00 Response status: 200 OK
...
2018-08-28T13:11:29+01:00 Elapsed time: 5.327 seconds

Run a simple shell command in a container

$ gostint-client -vault-token=@.vault_token \
  -url=https://127.0.0.1:13232 \
  -vault-url=http://127.0.0.1:18200 \
  -image=alpine \
  -run='["cat", "/etc/os-release"]'

NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.8.0
PRETTY_NAME="Alpine Linux v3.8"
HOME_URL="http://alpinelinux.org"
BUG_REPORT_URL="http://bugs.alpinelinux.org"

Running Ansible containers

$ gostint-client -vault-token=@.vault_token \
  -url=https://127.0.0.1:13232 \
  -vault-url=http://127.0.0.1:18200 \
  -image="jmal98/ansiblecm:2.5.5" \
  -entrypoint='["ansible"]' \
  -run='["--version"]'

ansible 2.5.5
  config file = None
  configured module search path = [u'/tmp/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.14 (default, Dec 14 2017, 15:51:29) [GCC 6.4.0]
$ gostint-client -vault-token=@.vault_token \
  -url=https://127.0.0.1:13232 \
  -vault-url=http://127.0.0.1:18200 \
  -image="jmal98/ansiblecm:2.5.5" \
  -entrypoint='["ansible"]' \
  -run='["-i", "127.0.0.1 ansible_connection=local,", "-m", "ping", "127.0.0.1"]'

127.0.0.1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
$ gostint-client -vault-token=@.vault_token \
  -url=https://127.0.0.1:13232 \
  -vault-url=http://127.0.0.1:18200 \
  -image="jmal98/ansiblecm:2.5.5" \
  -content=../gostint/tests/content_ansible_play \
  -run='["-i", "hosts", "play1.yml"]'

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [127.0.0.1]

TASK [include_vars] ************************************************************
ok: [127.0.0.1]

TASK [debug] *******************************************************************
ok: [127.0.0.1] => {
    "gostint": {
        "TOKEN": "secret-injected-by-gostint"
    }
}

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=3    changed=0    unreachable=0    failed=0   

Using Vault AppRole Authentication

Create a vault policy for the gostint-client’s approle

vault policy write gostint-client - <<EOF
path "auth/token/create" {
  capabilities = ["create", "read", "update", "delete", "list"]
}
path "auth/approle/role/gostint-role/secret-id" {
  capabilities = ["update"]
}
path "transit/encrypt/gostint" {
  capabilities = ["update"]
}
EOF

Create an AppRole (PUSH mode for this example) for the gostint-client:

vault write auth/approle/role/gostint-client-role \
  token_ttl=20m \
  token_max_ttl=30m \
  policies="gostint-client"

Get the Role_Id for the AppRole:

vault read /auth/approle/role/gostint-client-role/role-id

For this example we will use PUSH mode on the AppRole (note the secret_id was a random uuid) - you would probably prefer to use PULL mode in production:

vault write auth/approle/role/gostint-client-role/custom-secret-id \
  secret_id=7a32c590-aacc-11e8-a59c-8b71f9a0c1a4

Run gostint-client using the AppRole:

$ gostint-client -vault-roleid=43a03f77-7461-d4d2-c14d-76b39ea400d5 \
  -vault-secretid=7a32c590-aacc-11e8-a59c-8b71f9a0c1a4 \
  -url=https://127.0.0.1:13232 \
  -vault-url=http://127.0.0.1:18200 \
  -image=alpine \
  -run='["cat", "/etc/os-release"]'