RFC: concourse pki resources using cfssl


#1

I needed a set of resources for managing a simple PKI chain for setting up consul with TLS/SSL.

It stores all PKI resources in S3 under a single prefix, e.g. my-bucket/my-pki/root-ca.pem, etc.

I’ve created a set of resources to do such that, and since I thought it’d be easier to use with concourse if they were available on docker hub, I’ve also made it open source (under the MIT license).

Warning: I’m fairly new to python, and there aren’t any proper unit tests yet, so consider this somewhat alpha.

However, it’s got a fairly useful feature set I think so far, including:

  • supports alternative s3 provider (minio) in addition to AWS
  • uses metadata keys to store file checksums, and uses that to calculate versioning
  • since it only reads metadata it doesn’t need to download keys to check version
  • can optionally not download keys at all on an ‘in’ phase, supporting it as a pure trigger
  • supports one click renewal for root, intermediate, and leaf certs, while keeping the existing private key

How are you managing PKI with concourse, and what challenges have you ran into?

Thanks!


#2

I’ve got examples in the documentation, but here’s a complete example showing how you could set up a pipeline for your root, intermediate, and server leaf certs along with renewal.

---
resource_types:
- name: cfssl-root-ca
  type: docker-image
  source:
    repository: snapkitchen/concourse-cfssl-root-ca-resource
    tag: latest
- name: cfssl-intermediate-ca
  type: docker-image
  source:
    repository: snapkitchen/concourse-cfssl-intermediate-ca-resource
    tag: latest
- name: cfssl-leaf
  type: docker-image
  source:
    repository: snapkitchen/concourse-cfssl-leaf-resource
    tag: latest

resources:

- name: root-ca
  type: cfssl-root-ca
  source:
    bucket_name: ((bucket_name))
    access_key_id: ((access_key_id))
    secret_access_key: ((secret_access_key))
    region_name: ((region_name))
    prefix: ((prefix))
    endpoint: http://minio.service.local.consul:9000
    disable_ssl: true
- name: intermediate-ca
  type: cfssl-intermediate-ca
  source:
    bucket_name: ((bucket_name))
    access_key_id: ((access_key_id))
    secret_access_key: ((secret_access_key))
    region_name: ((region_name))
    prefix: ((prefix))
    endpoint: http://minio.service.local.consul:9000
    disable_ssl: true
- name: server-leaf
  type: cfssl-leaf
  source:
    leaf_name: server
    bucket_name: ((bucket_name))
    access_key_id: ((access_key_id))
    secret_access_key: ((secret_access_key))
    region_name: ((region_name))
    prefix: ((prefix))
    endpoint: http://minio.service.local.consul:9000
    disable_ssl: true

jobs:

- name: get-root-ca
  plan:
  - get: root-ca

- name: create-root-ca
  plan:
  - put: root-ca
    params:
      CN: RootCA
      names:
      - C: US
        L: Austin
        O: EXAMPLE
        OU: DevOps
        ST: Texas

- name: renew-root-ca
  plan:
  - put: root-ca
    params:
      action: renew

- name: get-intermediate-ca
  plan:
  - get: intermediate-ca

- name: create-intermediate-ca
  plan:
  - put: intermediate-ca
    params:
      CN: IntermediateCA
      names:
      - C: US
        L: Austin
        O: EXAMPLE
        OU: DevOps
        ST: Texas

- name: renew-intermediate-ca
  plan:
  - put: intermediate-ca
    params:
      action: renew

- name: get-server-leaf
  plan:
  - get: server-leaf

- name: create-server-leaf
  plan:
  - put: server-leaf
    params:
      CN: consul-server
      names:
      - C: US
        L: Austin
        O: EXAMPLE
        OU: DevOps
        ST: Texas
      leaf:
        usages:
        - signing
        - key encipherment
        - server auth
        hosts:
        - server.node.local.consul
        - localhost
        - 127.0.0.1

- name: renew-server-leaf
  plan:
  - put: server-leaf
    params:
      action: renew