When upgrating Puppet 5 to Puppet 6, one of the biggest changes for us was the removal of mcollective and ActiveMQ. Fortunately it wasn’t a total disappearance but a ful rewrite and a migration to choria, which offers much more possibilities.
Like Mcolvective, Choria is an orchestration tool working on a principle of client <-> broker <-> servers. Unlike the usal client/server models, Choria differs in the fact that we install servers on all our nodes to be managed which will be connected to one or multiple brokers. After a client sends an action message in the broker queue to be consumed by the servers. All of the work is mainly based on the nats nats librairy, and uses a x509 authentification, making the set very powerful with a low infrastructure cost (the documentation indicates the cost of a simple broker with 4G of RAM for 50k server to manage).
In our old mcollective architecture, we used an activemq cluster installed on 6 Puppetservers, then downgraded to 3 active nodes due to a useless and high connection consumption on the haproxy. For Choria we decided to start on the same architecture, and we decided to use the basic architecture, but we set up 3 brokers for a high availability.
Just before setting up the production I’ve decided to add two more targets:
The set up in Kubernestes is quite easy to access, a helm chart is available and contains pretty much everything that is necessary. It iss good to note, that for some reason I don’t know (probably related to the creations of the certificats), that your brokers are declared with StatefulSets. This can be usefull for your pod assignation.
The most complicated part is the Vault Ca integration. In fact the helm chart already proposes a CA management, but that’s not enough because it is a CA stored on a simple secret. In my case I’ve used cert-manager to declare mya Vault issuer with an appRole authentification:
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: vault-issuer
spec:
vault:
path: {{ .Values.vault.path }}
server: {{ .Values.vault.addr }}
auth:
appRole:
path: approle
roleId: {{ .Values.vault.roleId }}
secretRef:
name: cert-manager-vault-approle
key: secretId
Before it is necessary to have:
["list", "read", "create", "update"]
permissionscert-manager-vault-approle
with a key secretId
.values.yaml
, ex:---
vault:
addr: https://vault.wtf.org
roleId: db02de05-fa39-4855-059b-67221c5c2f63
path: pki_puppet_ca/sign/puppet
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: choria:csraccess
rules:
- apiGroups: ["cert-manager.io"]
resources: ["certificaterequests", "certificaterequest"]
verbs: ["get", "create", "delete", "post"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: choria:csracess
subjects:
- kind: ServiceAccount
name: choria-csraccess
apiGroup: ""
roleRef:
kind: Role
name: choria:csraccess
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: choria-csraccess
values.yaml
broker:
broker:
certManagerIssuer: vault-issuer
For use, thes choria clients must use an x509 certificate created by your CA with a Common Name related for your policies. Rather than creating certificates by ops and changing the policies everytime, I’ve created a dedicated host for client use and filtered by AD groups on the connection. Every userbthen had sudo rights to switch to choria
, was authorized to read the certificate that I generated with the puppetserverw puppetserver ca generate --certname choria.mcollective
.
We have a very basic usage of choria, principaly for packages listings or enable/disable puppet agent in few ms, but there are a lot of possibilities that I couldn’t test, like creating playbooks, use the tasks puppet or have a more advanced federated architecture.
When I created this environment, I learned that the
Common Name
on x509 certificates has been deprecated since May 2000 via RFC2818, but this field is mandatory when creating a certificate in a vault pki.