Post

Configure actions-runner-controller without cert-manager

Configure actions-runner-controller without cert-manager so that you can use self-signed or self-managed certificates to scale your GitHub runners

Overview

This legacy version of Actions Runner Controller is no longer supported by GitHub. You should switch to the Autoscaling Runner Sets version of ARC. This post is left here for historical purposes only.

Actions Runner Controller is a great way to set up self-scaling GitHub runners in a Kubernetes cluster. This allows teams to scale up their self-hosted runners as more jobs are queued throughout the day and scale down at night when there are fewer jobs running. There is a lot of documentation to digest in the repository, but for the most part, it’s relatively easy to get started with some basic scaling. The only prerequisite (other than having access to the Kubernetes cluster and administrative access to GitHub repo or organization) is cert-manager.

However, sometimes organizations have their own certificate requirements, and prefer to manage their own certificates vs. letting a tool like cert-manager manage them. This is where the current documentation is lacking and unclear. Other people have asked the same question, as well as my most recent customer, and we were able to figure it out so I’ll document it here!

Configuring without cert-manager

I’m going to be creating self-signed certificates, but you could imagine this working with certificates provided to you from the security team. If creating your own certificates, you will need openssl installed and callable via the command line.

1. Create RSA keys for CA cert and Server cert - this will output ca.key and server.key

1
2
openssl genrsa -out ca.key 4096
openssl genrsa -out server.key 4096

2. Create a CA configuration file (ca.conf) - the basicConstraints and keyUsage sections are required in order for the CA to be able to sign certificates

1
2
3
4
5
6
7
8
9
10
11
12
basicConstraints = CA:TRUE
keyUsage = cRLSign, keyCertSign
[req]
distinguished_name = req_distinguished_name
prompt = no
[req_distinguished_name]
C = US
ST = SomeState
L = SomeCity
O = SomeOrg
emailAddress = your@email.com
CN = actionrunners.yourorg.com

3. Create the CA certificate with the ca.conf file - this will output ca.crt

1
openssl req -x509 -new -sha512 -nodes -key ./ca.key -days 7307 -out ./ca.crt -config ./ca.conf

4. Optionally validate that the CA certificate created successfully

1
openssl x509 -noout -text -in ./ca.crt

5. Create your Server certificate config file - ie server.conf

  • All 3 SANs (alt_names) are needed
  • For the 3rd alt_name, the actions-runner-system is the namespace - if you are installing into a different namespace, replace actions-runner-system with the namespace you are installing to (ie: default)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[req]
default_bits = 4096
prompt = no
default_md = sha256
x509_extensions = v3_req
distinguished_name = dn

[dn]
C = US
ST = SomeState
L = SomeCity
O = SomeOrg
emailAddress = your@email.com
CN = actionrunners.yourorg.com

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = webhook-service.actions-runner-system.svc
DNS.2 = webhook-service.actions-runner-system.svc.cluster.local
DNS.3 = actions-runner-controller-webhook.actions-runner-system.svc

6. Create the server Certificate Signing Request (csr) - this will outut server.csr

1
openssl req -new -key ./server.key -out ./server.csr -config ./server.conf

7. Create your Server certificate - this will output server.crt

1
2
3
openssl x509 -req -in ./server.csr -CA ./ca.crt -CAkey ./ca.key \
  -CAcreateserial -out ./server.crt -days 10000 \
  -extensions v3_req -extfile ./server.conf

8. Optionally inspect your Server cert to make sure it has the Subject Alternate Names (SANs, aka the alt_names from step #5)

1
openssl x509 -noout -text -in ./server.crt

9. Base64 the CA cert and copy to clipboard (pbcopy is a macOS command, if running elsewhere just echo $CA_BUNDLE and copy)

1
2
CA_BUNDLE=$(cat ca.crt | base64)
echo $CA_BUNDLE | pbcopy

10. Set the admissionWebHooks.caBundle value in the values.yaml file to the base64 value of the CA cert - you may have to remove the extra {} under admissionWebHooks

1
2
3
admissionWebHooks:
  # {} # need to remove this
  caBundle: "Ci0tL..."

11. In the values.yaml file, ensure certManagerEnabled is set to false

1
certManagerEnabled: false

12. Create your certificate secrets using kubectl - both of these are needed

1
2
3
4
kubectl create secret tls webhook-server-cert -n actions-runner-system \
  --cert=./server.crt  --key=./server.key
kubectl create secret tls actions-runner-controller-serving-cert -n actions-runner-system \
  --cert=./server.crt  --key=./server.key

13. Run the helm upgrade command to install the controller

1
2
3
helm upgrade --install --namespace actions-runner-system --create-namespace \ 
  --wait actions-runner-controller actions-runner-controller/actions-runner-controller \
  --values ./values.yaml

Note: Make sure to you have ran the helm repo add command already

14. Ensure that your actions-runner-controller pod in the actions-runner-system namespace has started - if it fails, describe the pod and check the events

15. Deploy your runner configuration - my example with org runners and metric-based scaling

1
kubectl apply -f runner.yaml --namespace default

16. Ensure that your runner pods have started (describe them if not); check GitHub to see if your runner(s) show there also

Here’s me running k9s to visualize the pods and ensure they are running: Using k9s to ensure pods are running The controller running in the actions-runner-system namespace; the runner pods running in the default namespace

Corresponding runners show up as org runners in GitHub: Org runners in GitHub Runners with the same name as the pod name show up as org runners in GitHub

Summary

actions-runner-controller is great, but sometimes you need some good trial-and-error to do things off the beaten path. Luckily, we were able to figure out how to configure the controller without using cert-manager by interpreting the errors we saw when describing the failing pods.

As an enhancement, I could see you wanting a separate certificate for the actions-runner-controller-serving-cert and webhook-server-cert in step #12 - but I’ll leave further certificate optimizations to the certificate pros.

Feel free to ask any questions or share any enhancements!

This post is licensed under CC BY 4.0 by the author.