step-ca: Deploy Step CA service
[Step CA] is an open-source online X.509 and SSH certificate authority service. It supports issuing certificates via various protocols, including ACME and its own HTTP API via the `step` command-line utility. Clients can authenticate using a variety of methods, such as JWK, Open ID Connect, or mTLS. This makes it very flexible and easy to introduce to an existing ecosystem. Although the CA service is mostly stateless, it does have an on-disk database where stores some information, notably the list of SSH hosts for which it has signed certificates. Most other operations, though, do not require any persistent state; the service does not keep track of every single certificate it signed, for example. It can be configured to store authentication information (referred to as "provisioners") in the database instead of the configuration file, by enabling the "remote provisioner management" feature. This has the advantage of being able to modify authentication configuration without updating a Kubernetes ConfigMap and restarting the service. The official Step CA documentation recommends using the `step ca init` command initialize a new certificate authority. This command performs a few steps: * Generates an ECDSA key pair and uses it to create a self-signed root certificate * Generates a second ECDSA key pair and signs an intermediate CA certificate using the root CA key * Generates an ECDSA key pair and SSH root certificate * Creates a `ca.json` configuration file These steps can be performed separately, and in fact, I created the intermediate CA certificate and signed it with the (offline) *dch Root CA* certificate. When the service starts for the first time, because `authority/enableAdmin` is `true` and `authority/provisioners` is empty, a new "Admin JWK" provisioner will be created automatically. This key will be encrypted with the same password used to encrypt the intermediate CA certificate private key, and can be used to create other provisioners. [Step CA]: https://smallstep.com/docs/step-ca/dch-webhooks-secrets
parent
6cd7eae0d3
commit
0a9596d8bd
|
@ -0,0 +1,3 @@
|
|||
*.key
|
||||
password
|
||||
ssh_*_key
|
|
@ -0,0 +1,100 @@
|
|||
# Step CA
|
||||
|
||||
[Step CA] is an open-source online X.509 and SSH certificate authority servier.
|
||||
It provides an HTTP API for remote control via the `step` command, which is
|
||||
used by clients for certificate issuance and administrators for configuration
|
||||
and control. It also supports other certificate issuance protocols, including
|
||||
[ACME]. Clients can authenticate using a variety of protocols, such as JWK,
|
||||
OpenID Connect, mTLS, and more.
|
||||
|
||||
|
||||
## Offline Root CA
|
||||
|
||||
The *dch Root CA R2* private key is managed externally from Step CA. It is
|
||||
stored offline (on a flash drive in a fireproof save). Only the CA certificate
|
||||
is used by the online CA service, where it is provided to clients to include in
|
||||
as a trust anchor in their respective certificate stores.
|
||||
|
||||
*dch Root CA R2* replaces *dch Root CA R1*, which has not been used for some
|
||||
time.
|
||||
|
||||
|
||||
## Online Intermediate CA
|
||||
|
||||
Step CA manages the *dch CA R2* intermediate certificate authority. The
|
||||
private key for this CA is stored in the `intermediate_ca.key` file, encrypted
|
||||
with the password in `password`. This key pair is needed by the online CA to
|
||||
sign end-entity certificates.
|
||||
|
||||
|
||||
## SSH CA
|
||||
|
||||
In addition to X.509 (TLS) certificates, Step CA can also manage SSH
|
||||
certificates. These can be used in place of "plain" SSH keys that must be
|
||||
managed out-of-band (i.e. `~/.ssh/known_hosts` and `~/.ssh/authorized_keys`).
|
||||
|
||||
Instead of maintaining a database of hosts' public keys, clients can trust the
|
||||
CA certificate that signs the hosts' certificates. To do so, simply add a
|
||||
single line to `~/.ssh/known_hosts`:
|
||||
|
||||
```
|
||||
@cert-authority *.pyrocufflink.blue ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ8KfNjDh0R/jCmPcJrVafvmuw5JZw+cKoy9RCYNwHsRwPoRHfyzjV1VUZolJfEz+Qm3u+mgYJ/oSquCelY84xE=
|
||||
```
|
||||
|
||||
Any host with a hostname that matches `*.pyrocufflink.blue` and presents a
|
||||
certificate signed by the listed certificate will be automatically trusted; the
|
||||
`ssh` client will not prompt for manual key verification on the first
|
||||
connection.
|
||||
|
||||
Similarly, hosts can trust client keys that are signed by the CA by *either*
|
||||
adding the certificate to per-user `~/.ssh/authorized_keys` files *or* by
|
||||
setting the global `TrustedUserCAKeys` parameter in the SSH server
|
||||
configuration.
|
||||
|
||||
`~/.ssh/authorized_keys`:
|
||||
```
|
||||
cert-authority ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBImIoTTmhynCVy/vJ/Q2bWydzqVsvwhGvDgBbklw0eDt8UEbbP9HHPhxiMDtiAhbvRTg5BhYVAlR1MgdooT5dwQ=
|
||||
```
|
||||
|
||||
`/etc/ssh/sshd_config`:
|
||||
```
|
||||
TrustedUserCAKeys /etc/ssh/ca.pub
|
||||
```
|
||||
|
||||
`/etc/ssh/ca.pub`:
|
||||
```
|
||||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBImIoTTmhynCVy/vJ/Q2bWydzqVsvwhGvDgBbklw0eDt8UEbbP9HHPhxiMDtiAhbvRTg5BhYVAlR1MgdooT5dwQ=
|
||||
```
|
||||
|
||||
SSH host certificates are typically valid for 30 days, so hosts need to have
|
||||
some automation in place to automatically renew their certificates. Using the
|
||||
"SSHPOP" provisioner, hosts can use the `step ssh renew` command to renew their
|
||||
certificates; existing signed SSH certificates are usable as authentication
|
||||
credentials.
|
||||
|
||||
SSH user certificates are typically valid for 24 hours. Clients will need to
|
||||
request a new certificate every day using the `step ssh login` command:
|
||||
|
||||
```sh
|
||||
step ssh login --provisioner=authelia dustin
|
||||
```
|
||||
|
||||
Note the `--provisioner=authelia` argument seems to be required, even if a
|
||||
default provisioner is specified in `~/.step/config/defaults.json`.
|
||||
|
||||
The final positional argument is the name of the *remote* SSH user, *not* the
|
||||
user logging in to the OIDC IdP.
|
||||
|
||||
|
||||
## NodePort Service (No Ingress)
|
||||
|
||||
Step CA supports authenticating clients using mTLS, such as to renew a user
|
||||
certificate. For this to work, the client must communicate directly with the
|
||||
server; proxies and load balancers must not intercept the communication or
|
||||
provide TLS termination, as then the server would not have access to the client
|
||||
certificate. As such, the service is exposed as a NodePort and not via an
|
||||
Ingress.
|
||||
|
||||
|
||||
[Step CA]: https://smallstep.com/docs/step-ca/
|
||||
[ACME]: https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"root": "certs/root_ca.crt",
|
||||
"federatedRoots": null,
|
||||
"crt": "certs/intermediate_ca.crt",
|
||||
"key": "secrets/intermediate_ca.key",
|
||||
"address": ":32599",
|
||||
"insecureAddress": "",
|
||||
"dnsNames": [
|
||||
"ca.pyrocufflink.blue"
|
||||
],
|
||||
"ssh": {
|
||||
"hostKey": "secrets/ssh_host_ca_key",
|
||||
"userKey": "secrets/ssh_user_ca_key"
|
||||
},
|
||||
"logger": {
|
||||
"format": "text"
|
||||
},
|
||||
"db": {
|
||||
"type": "badgerv2",
|
||||
"dataSource": "db",
|
||||
"badgerFileLoadingMode": ""
|
||||
},
|
||||
"authority": {
|
||||
"enableAdmin": true,
|
||||
"provisioners": []
|
||||
},
|
||||
"tls": {
|
||||
"cipherSuites": [
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
||||
],
|
||||
"minVersion": 1.2,
|
||||
"maxVersion": 1.3,
|
||||
"renegotiation": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICCTCCAa+gAwIBAgIUOrt38QEPFGRaBSZgyuDNQPCLUZowCgYIKoZIzj0EAwIw
|
||||
QDELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD0R1c3RpbiBDLiBIYXRjaDEXMBUGA1UE
|
||||
AwwORENIIFJvb3QgQ0EgUjIwHhcNMjMwOTI4MDI0NzMwWhcNMjMxMDI4MDI0NzMw
|
||||
WjAUMRIwEAYDVQQDEwlkY2gtY2EgUjIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
|
||||
AAQ1rK98igj6Y5lbeP8HS1zqQCtkcmz8uk1jp4VgznWT3Q8BanjA55UHQi/xx4xz
|
||||
BYu4QIkJhtqcR5a7YXSr7fQvo4GyMIGvMB0GA1UdDgQWBBQGy1GZZxrCjGDiIGdR
|
||||
YhTMZZqhkTAfBgNVHSMEGDAWgBTM+d8kb1koGmKRtJs4gN9zYa+6oTASBgNVHRMB
|
||||
Af8ECDAGAQH/AgEAMAsGA1UdDwQEAwIBhjBMBggrBgEFBQcBAQRAMD4wPAYIKwYB
|
||||
BQUHMAKGMGh0dHBzOi8vZHVzdGluLmhhdGNoLm5hbWUvZGNoLWNhL2RjaC1yb290
|
||||
LWNhLmNydDAKBggqhkjOPQQDAgNIADBFAiADzZFTGwWNkwZF1U7uZEon7D6sLmCS
|
||||
WGftl3/IgOrpwwIhAM8bE5UlY3gXt8AObj8VQgGk5Bh38jmOXnDaK0iRz1qm
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,28 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: step-ca
|
||||
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- step-ca.yaml
|
||||
|
||||
configMapGenerator:
|
||||
- name: step-ca-config
|
||||
files:
|
||||
- ca.json
|
||||
|
||||
- name: step-ca-certs
|
||||
files:
|
||||
- root_ca.crt
|
||||
- intermediate_ca.crt
|
||||
- ssh_host_ca_key.pub
|
||||
- ssh_user_ca_key.pub
|
||||
|
||||
secretGenerator:
|
||||
- name: step-ca
|
||||
files:
|
||||
- intermediate_ca.key
|
||||
- password
|
||||
- ssh_host_ca_key
|
||||
- ssh_user_ca_key
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: step-ca
|
|
@ -0,0 +1,12 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIBxDCCAWqgAwIBAgIUbHz2tssa09zsHk+EdGD3QKprMKQwCgYIKoZIzj0EAwQw
|
||||
QDELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD0R1c3RpbiBDLiBIYXRjaDEXMBUGA1UE
|
||||
AwwORENIIFJvb3QgQ0EgUjIwHhcNMjMwOTI0MjA1MzA5WhcNNDMwOTE5MjA1MzA5
|
||||
WjBAMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPRHVzdGluIEMuIEhhdGNoMRcwFQYD
|
||||
VQQDDA5EQ0ggUm9vdCBDQSBSMjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE2D
|
||||
NJHRcjuA19ZoprBKaxIfUxAbz6LigM7dgtO6+isaMlxRAVJmsITADIE/22RrUDgD
|
||||
Ofkt2iZTUjMrz3AxXhWjQjBAMB0GA1UdDgQWBBTM+d8kb1koGmKRtJs4gN9zYa+6
|
||||
oTASBgNVHRMBAf8ECDAGAQH/AgEBMAsGA1UdDwQEAwIBBjAKBggqhkjOPQQDBANI
|
||||
ADBFAiEA2Ka8mMiAFLmrFWt0dAml247re2+i4UPhyHcOBfNK+goCIHv+vEw7CHZQ
|
||||
irIa697nfe4KiXIMwHlAMS1+1QZohFDC
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1 @@
|
|||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ8KfNjDh0R/jCmPcJrVafvmuw5JZw+cKoy9RCYNwHsRwPoRHfyzjV1VUZolJfEz+Qm3u+mgYJ/oSquCelY84xE=
|
|
@ -0,0 +1 @@
|
|||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBImIoTTmhynCVy/vJ/Q2bWydzqVsvwhGvDgBbklw0eDt8UEbbP9HHPhxiMDtiAhbvRTg5BhYVAlR1MgdooT5dwQ=
|
|
@ -0,0 +1,128 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: step-ca
|
||||
namespace: step-ca
|
||||
labels:
|
||||
app.kubernetes.io/name: step-ca
|
||||
app.kubernetes.io/component: step-ca
|
||||
app.kubernetes.io/instance: step-ca
|
||||
app.kubernetes.io/part-of: step-ca
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: step-ca
|
||||
namespace: step-ca
|
||||
labels:
|
||||
app.kubernetes.io/name: step-ca
|
||||
app.kubernetes.io/component: step-ca
|
||||
app.kubernetes.io/instance: step-ca
|
||||
app.kubernetes.io/part-of: step-ca
|
||||
spec:
|
||||
ports:
|
||||
- port: 32599
|
||||
nodePort: 32599
|
||||
name: step-ca
|
||||
selector:
|
||||
app.kubernetes.io/name: step-ca
|
||||
app.kubernetes.io/component: step-ca
|
||||
app.kubernetes.io/instance: step-ca
|
||||
type: NodePort
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: step-ca
|
||||
namespace: step-ca
|
||||
labels:
|
||||
app.kubernetes.io/name: step-ca
|
||||
app.kubernetes.io/component: step-ca
|
||||
app.kubernetes.io/instance: step-ca
|
||||
app.kubernetes.io/part-of: step-ca
|
||||
spec:
|
||||
serviceName: step-ca
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: step-ca
|
||||
app.kubernetes.io/component: step-ca
|
||||
app.kubernetes.io/instance: step-ca
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: step-ca
|
||||
app.kubernetes.io/component: step-ca
|
||||
app.kubernetes.io/instance: step-ca
|
||||
spec:
|
||||
enableServiceLinks: false
|
||||
containers:
|
||||
- name: step-ca
|
||||
image: docker.io/smallstep/step-ca:0.25.0
|
||||
workingDir: /step
|
||||
env:
|
||||
- name: CONFIGPATH
|
||||
value: /step/config/ca.json
|
||||
- name: PWDPATH
|
||||
value: /step/secrets/password
|
||||
- name: STEPPATH
|
||||
value: /step
|
||||
ports:
|
||||
- containerPort: 32599
|
||||
name: step-ca
|
||||
readinessProbe: &probe
|
||||
httpGet:
|
||||
port: 32599
|
||||
path: /health
|
||||
scheme: HTTPS
|
||||
failureThreshold: 3
|
||||
periodSeconds: 60
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 1
|
||||
startupProbe:
|
||||
<<: *probe
|
||||
failureThreshold: 30
|
||||
periodSeconds: 3
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 1
|
||||
volumeMounts:
|
||||
- mountPath: /step/certs
|
||||
name: certs
|
||||
readOnly: true
|
||||
- mountPath: /step/config
|
||||
name: config
|
||||
readOnly: true
|
||||
- mountPath: /step/db
|
||||
name: data
|
||||
subPath: db
|
||||
- mountPath: /step/secrets
|
||||
name: secrets
|
||||
readOnly: true
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
fsGroup: 1000
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: step-ca-config
|
||||
- name: certs
|
||||
configMap:
|
||||
name: step-ca-certs
|
||||
- name: secrets
|
||||
secret:
|
||||
secretName: step-ca
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: step-ca
|
||||
|
||||
|
Loading…
Reference in New Issue