maraino / webhooks

πŸͺA sample webhook app for step-ca

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Webhooks

Webhooks is a sample application that can be used with step-ca to allow requests with an ACME device-attest-01 flow.

It uses a small sqlite3 database that contains a table with the devices that are allowed to get a certificate using the ACME DA flow.

Building Webhooks

To build webhooks, just run the following commands:

$ make
go build -o bin/webhooks main.go
dbmate --url "sqlite:db/database.sqlite3" --no-dump-schema up

In the second command, we are using the database migration tool dbmate to setup the database.

Running Webhooks

Webhooks can run with or without TLS support. For this example, we will use TLS, more specifically, mTLS.

First, let's add our device to the database. If Jane is using a YubiKey with serial number 112233, we need to register it in the database:

$ sqlite3 db/database.sqlite3 \
"insert into devices(id, type, owner, allow, data, created_at) values ('112233', 'YubiKey', 'jane@example.org', true, '{\"email\":\"jane@example.org\"}', unixepoch())"

We will generate a TLS certificate for webhooks using an already configured step-ca. For this example everything is running in localhost:

$ step ca certificate localhost localhost.crt localhost.key
βœ” Provisioner: admin (JWK)
βœ” CA: https://localhost:9000
βœ” Certificate: localhost.crt
βœ” Private Key: localhost.key
$ step ca root > root_ca.crt

And will run webhooks with TLS support using the --cert and --key flags, and we will require a client certificate of a specific CA using the flag --root.

$ bin/webhooks --cert localhost.crt --key localhost.key --root root_ca.crt
2023/03/02 17:29:38 starting https server at :3000

And finally, we need to configure step-ca with a provisioner that might look like this:

{
    "type": "ACME",
    "name": "attestation",
    "challenges": [
        "device-attest-01"
    ],
    "attestationFormats": [
        "step"
    ],
    "options": {
        "webhooks": [
            {"name": "devices", "url": "https://localhost:3000/devices", "kind": "ENRICHING"}
        ]
    }
}

Now with step-ca running, Jane will be able to get a certificate:

$ step ca certificate --provisioner attestation --attestation-uri 'yubikey:slot-id=9a?piv-value=123456' 112233 jane.crt jane.key
βœ” Provisioner: attestation (ACME)
Using Device Attestation challenge to validate "112233" . done!
Waiting for Order to be 'ready' for finalization .. done!
Finalizing Order .. done!
βœ” Certificate: jane.crt
βœ” Private Key: yubikey:slot-id=9a?piv-value=123456

But John won't be able to get a certificate with his YubiKey:

$ step ca certificate --provisioner attestation --attestation-uri 'yubikey:slot-id=9a?piv-value=123456' 998877 john.crt john.key
βœ” Provisioner: attestation (ACME)
Using Device Attestation challenge to validate "998877" . done!
Waiting for Order to be 'ready' for finalization .. done!
Finalizing Order .error finalizing order: The server experienced an internal error

In our example, the response from webhooks is like this:

{
    "data": {
        "email": "jane@example.org"
    },
    "allow": true
}

We can use that data property to extend the final certificate. With an step-ca certificate template like this:

{
    "subject": {{ toJson .Subject }},
    "sans": {{ toJson .SANs }},
{{- with .Webhooks.devices.email }}
    "emailAddresses": [{{ toJson . }}],
{{- end }}
{{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }}
    "keyUsage": ["keyEncipherment", "digitalSignature"],
{{- else }}
    "keyUsage": ["digitalSignature"],
{{- end }}
    "extKeyUsage": ["serverAuth", "clientAuth"]
}

Jane will get a certificate with her permanent identifier and her email address:

X509v3 Subject Alternative Name:
    email:jane@example.org
    Permanent Identifier: 112233

About

πŸͺA sample webhook app for step-ca

License:Apache License 2.0


Languages

Language:Go 98.3%Language:Makefile 1.7%