Webhooks
Webhooks let you enrich X.509 or SSH certificates with data requested from an external endpoint. The CA fetches key/value pairs from a configured webhook when a CSR is being processed, and the webhook data is passed along to the provisioner's certificate template.
Attach webhooks to provisioners via the step ca provisioner webhook
command group.
Quickstart
We've created an example webhook server. You can use it to try out webhooks locally, or as the basis of your own custom webhook integration.
-
Initialize a new Certificate Authority with remote management enabled.
step ca init --remote-management --context webhooks
Then, in another window, start
step-ca
:step-ca --context webhooks
-
Clone the example webhook repository.
git clone https://github.com/smallstep/webhooks.git cd webhooks
-
Generate a server certificate for your webhook server.
step ca certificate localhost webhook.crt webhook.key
-
Export your root CA certificate for the webhook server.
step ca root > root_ca.crt
-
Add a new provisioner to associate with your webhook. When asked, the default admin username is
step
.step ca provisioner add my_provisioner --create
-
Add a webhook to your provisioner for a webhook server that will be listening on
localhost:9443
.☠️ Don't add your webhook to the default (administrative) CA provisioner! You may lock yourself out of your CA.
step ca provisioner webhook add my_provisioner people --url 'https://localhost:9443/{{ .Token.sub }}'
This command will print out the ID and secret for the
people
webhook. -
Update the
webhookIDsToSecrets
map in the webhook server'smain.go
file with the ID and secret printed above. -
Update the
db
map in the webhook server'smain.go
file with the Common Name (CN) you will be issuing test certificates for. -
Start the webhook server:
go run main.go
-
Add a template to the provisioner to incorporate the data returned from the
people
webhook:cat <<EOF > external_ou.tpl { "subject": { "organizationalUnit": {{ toJson .Webhooks.people.role }} } } EOF step ca provisioner update my_provisioner --x509-template external_ou.tpl
-
Get a certificate with the provisioner you configured earlier:
step ca certificate andrew@smallstep.com my.crt my.key --provisioner my_provisioner
-
Inspect the certificate. Notice that the user's role returned from the webhook server appears in the OU.
step certificate inspect my.crt --format json | jq .subject
Implementation Details
Webhook Server Response
The webhook server must include "allow": true
in the response body,
or step-ca
will refuse to sign the certificate request.
The step-ca
template engine augments the template data with the data
object in the response body.
For example, a webhook server could send the following JSON response:
{
"allow": true,
"data": {
"role": "eng"
}
}
A template on the provisioner will then be able to reference the response under the path .Webhooks.webhook_name
.
If the webhook was named people
, the role in the webhook response could be accessed in a template under the field .Webhooks.people.role
.
Requests
All requests will use the POST
method to send a JSON body to the webhook server containing a timestamp
field.
Additional data will vary based on the type of the certificate being signed.
The webhooks server example repository contains examples in Go of parsing webhook request bodies for both X.509 and SSH certificate requests.
X.509 Request Body
For X.509 certificates, step-ca
will include an x509CertificateRequest
field
that will hold a JSON representation of the request
using the same schema as x509 template functions
with a few extra fields.
Webhooks for ACME device-attest-01
You can use webhooks to enrich device certificates issued via an ACME device-attest-01
challenge.
When used with the ACME provisioner
and the ACME device-attest-01
challenge,
the request body will also contain the verified device ID in the attestationData.permanentIdentifier
field.
Webhooks for SCEP challenges
Webhooks can also be used to validate SCEP challenges when a SCEP provisioner is in use. Add a webhook to your SCEP provisioner using the CLI:
step ca provisioner webhook add my_scep_provisioner scepchallenge --url 'https://localhost:9443/scepvalidation' --kind SCEPCHALLENGE
When a SCEP client requests a certificate with a challenge password embedded, the webhook server will receive a request.
The request will contain the scepChallenge
provided by the client and the scepTransactionID
from the SCEP request.
Unlike webhooks configured on other provisioners, when a single SCEP provisioner is configured with multiple SCEPCHALLENGE
webhooks,
only a single one of the SCEPCHALLENGE
webhooks needs to indicate the request is allowed for the certificate to be issued.
SSH Request Body
For SSH certificates step-ca
will include an sshCertificateRequest
field with data from the request.
Authentication
Your webhook server must authenticate each request from the CA. To achieve this, the CA sends a signature of its payload in the webhook request header, and the webhook server must confirm this signature. The signature also tells the webhook server which webhook is currently being executed.
In addition the the signature header, you can optionally enable two other authentication schemes:
- Authorization Header
The CA can send a bearer token or username and password in anAuthentication
header. - Mutual TLS
The webhook server can require and verify the connection using mutual TLS. The CA will provide a client certificate when requested.
Signature and ID Headers
Every webhook has a unique secret that will be displayed when the webhook is created
via step ca provisioner webhook add
.
step-ca
will include a signature of the payload in the X-Smallstep-Signature
header.
The webhook ID will also be included in the X-Smallstep-Webhook-ID
header
to help associate the correct signing secret with the webhook request.
Webhook servers must compute an HMAC with the SHA256 hash function,
using the webhook signing secret as the key and the request body as the message.
See the webhook server example repository for an example of verifying the signature.
Authorization Header (optional)
For an additional layer of security, step-ca
may be configured to send
either a bearer token
or a username:password
in the Authorization
header.
To use a bearer token, run:
step ca provisioner webhook update my_provisioner my_webhook --bearer-token abc123xyz
Or, to use basic authentication, run:
step ca provisioner webhook update my_provisioner my_webhook --basic-auth-username user --basic-auth-password-file pass.txt
Mutual TLS Authentication (optional)
You can also use mutual TLS to authenticate step-ca
as a client of your webhook server.
By default, step-ca
will send the CA's self-generated leaf certificate
when asked for a client certificate as part of the TLS handshake.
To enable mutual TLS,
configure your webhook server to request and verify a client certificate
that chains up to your root CA certificate.