From 754670ad12357e201de30feb3030077483a54ee6 Mon Sep 17 00:00:00 2001 From: Sebastian Tiedtke Date: Mon, 28 Jan 2019 17:31:06 -0600 Subject: [PATCH] Add basic federation example (#26) Add basic federation example --- examples/README.md | 104 ++++++++++++++++++ examples/basic-federation/client/main.go | 44 ++++++++ .../pki/cloud/certs/intermediate_ca.crt | 12 ++ .../pki/cloud/certs/kubernetes_root_ca.crt | 11 ++ .../pki/cloud/certs/root_ca.crt | 11 ++ .../pki/cloud/config/ca.federated.json | 40 +++++++ .../basic-federation/pki/cloud/config/ca.json | 40 +++++++ .../pki/cloud/secrets/intermediate_ca_key | 8 ++ .../pki/cloud/secrets/root_ca_key | 8 ++ .../pki/kubernetes/certs/cloud_root_ca.crt | 11 ++ .../pki/kubernetes/certs/intermediate_ca.crt | 12 ++ .../pki/kubernetes/certs/root_ca.crt | 11 ++ .../pki/kubernetes/config/ca.federated.json | 40 +++++++ .../pki/kubernetes/config/ca.json | 40 +++++++ .../kubernetes/secrets/intermediate_ca_key | 8 ++ .../pki/kubernetes/secrets/root_ca_key | 8 ++ examples/basic-federation/server/main.go | 73 ++++++++++++ 17 files changed, 481 insertions(+) create mode 100644 examples/basic-federation/client/main.go create mode 100644 examples/basic-federation/pki/cloud/certs/intermediate_ca.crt create mode 100644 examples/basic-federation/pki/cloud/certs/kubernetes_root_ca.crt create mode 100644 examples/basic-federation/pki/cloud/certs/root_ca.crt create mode 100644 examples/basic-federation/pki/cloud/config/ca.federated.json create mode 100644 examples/basic-federation/pki/cloud/config/ca.json create mode 100644 examples/basic-federation/pki/cloud/secrets/intermediate_ca_key create mode 100644 examples/basic-federation/pki/cloud/secrets/root_ca_key create mode 100644 examples/basic-federation/pki/kubernetes/certs/cloud_root_ca.crt create mode 100644 examples/basic-federation/pki/kubernetes/certs/intermediate_ca.crt create mode 100644 examples/basic-federation/pki/kubernetes/certs/root_ca.crt create mode 100644 examples/basic-federation/pki/kubernetes/config/ca.federated.json create mode 100644 examples/basic-federation/pki/kubernetes/config/ca.json create mode 100644 examples/basic-federation/pki/kubernetes/secrets/intermediate_ca_key create mode 100644 examples/basic-federation/pki/kubernetes/secrets/root_ca_key create mode 100644 examples/basic-federation/server/main.go diff --git a/examples/README.md b/examples/README.md index 4e47f3f8..06e7384a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -451,6 +451,110 @@ Removing docker_ca_1 ... done Removing network docker_default ``` +## Basic Federation + +The [basic-federation example](basic-federation) showcases how to securely facilitate communication between relying parties of multiple autonomous certificate authorities. Federation is what's required when services are spread between multiple independent Kubernetes clusters, public clouds, and/or serverless cloud functions to enable service communication across boundaries. + +This example uses a pre-generated PKI (public/private key material). Do not use pre-generated PKIs for dev, staging, or production purposes outside of this example. + +# Launch Online CAs + +Bring up two online CAs; `Cloud CA` and `Kubernetes CA`. + +```bash +$ step-ca ./pki/cloud/config/ca.federated.json +Please enter the password to decrypt intermediate_ca_key: password +2019/01/22 13:38:52 Serving HTTPS on :1443 ... +``` + +```bash +$ step-ca ./pki/kubernetes/config/ca.federated.json +Please enter the password to decrypt intermediate_ca_key: password +2019/01/22 13:39:44 Serving HTTPS on :2443 ... +``` + +Notice the difference between the two configuration options below. `Cloud CA` will list `Kubernetes CA` in the `federatedRoots` section and vice versa for the federated options. + +```bash +$ diff pki/cloud/config/ca.json pki/cloud/config/ca.federated.json +3c3 +< "federatedRoots": [], +--- +> "federatedRoots": ["pki/cloud/certs/kubernetes_root_ca.crt"], +``` + +# Bring up Demo Server + +This demo server leverages step's [SDK](https://godoc.org/github.com/smallstep/certificates/ca) to obtain certs, automatically renew them, and fetch a bundle of trusted roots. When it starts up it will report what root certificates it will use to authenticate client certs. + +```bash +go run server/main.go $(step ca token \ + --ca-url https://localhost:1443 \ + --root ./pki/cloud/certs/root_ca.crt \ + 127.0.0.1) +✔ Key ID: EE1ZiqkMaxsUdpz8SCSkRBzwK9TWUoidQnMnJ8Eryn8 (sebastian@smallstep.com) +✔ Please enter the password to decrypt the provisioner key: password +Server is using federated root certificates +Accepting certs anchored in CN=Smallstep Public Cloud Root CA +Accepting certs anchored in CN=Smallstep Kubernetes Root CA +Listening on :8443 ... +``` + +# Run Demo Client + +Similarly step's [SDK](https://godoc.org/github.com/smallstep/certificates/ca) provides a client option to mutually authenticate connections to servers. It automatically handles cert bootstrapping, renewal, and fetches a bundle of trusted roots. The demo client will send HTTP requests to the demo server periodically (every 5s). + +```bash +$ go run client/main.go $(step ca token sdk_client \ + --ca-url https://localhost:2443 \ + --root ./pki/kubernetes/certs/root_ca.crt) +✔ Key ID: S5gYgpeqcIAgc1Zr4myZXpgJ_Ao4ryS6F6wqg9o8RYo (sebastian@smallstep.com) +✔ Please enter the password to decrypt the provisioner key: password +Server responded: Hello sdk_client (cert issued by 'Smallstep Kubernetes Root CA') at 2019-01-23 00:51:38.576648 +0000 UTC +``` + +# Curl as Client + +While the demo client provides a convenient way to periodically send requests to the demo server curl in combination with a client cert from `Kubernetes CA` can be used to hit the server instead: + +```bash +$ step ca certificate kube_client kube_client.crt kube_client.key \ + --ca-url https://localhost:2443 \ + --root pki/kubernetes/certs/root_ca.crt +✔ Key ID: S5gYgpeqcIAgc1Zr4myZXpgJ_Ao4ryS6F6wqg9o8RYo (sebastian@smallstep.com) +✔ Please enter the password to decrypt the provisioner key: +✔ CA: https://localhost:2443/1.0/sign +✔ Certificate: kube_client.crt +✔ Private Key: kube_client.key +``` + +Federation relies on a bundle of multiple trusted roots which need to be fetched before passed into curl. + +```bash +$ step ca federation --ca-url https://localhost:1443 \ + --root pki/cloud/certs/root_ca.crt \ + federated.pem +The federation certificate bundle has been saved in federated.pem. +``` + +Passing the cert (issued by `Kubernetes CA`) into curl using the appropriate command line flags: + +```bash +$ curl -i --cacert federated.pem \ + --cert kube_client.crt \ + --key kube_client.key \ + https://127.0.0.1:8443 + +HTTP/2 200 +content-type: text/plain; charset=utf-8 +content-length: 105 +date: Mon, 28 Jan 2019 15:24:54 GMT + +Hello kube_client (cert issued by 'Smallstep Kubernetes Root CA') at 2019-01-28 15:24:54.864373 +0000 UTC +``` + +Since the demo server is enrolled with the federated `Cloud CA` that trusts certs issued by the `Kubernetes CA` through federation the connection is successfully established. + ## Configuration Management Tools Configuration management tools such as Puppet, Chef, Ansible, Salt, etc. make diff --git a/examples/basic-federation/client/main.go b/examples/basic-federation/client/main.go new file mode 100644 index 00000000..e8c5140e --- /dev/null +++ b/examples/basic-federation/client/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "time" + + "github.com/smallstep/certificates/ca" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0]) + os.Exit(1) + } + + token := os.Args[1] + + // make sure to cancel the renew goroutine + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client, err := ca.BootstrapClient(ctx, token, ca.AddFederationToRootCAs()) + if err != nil { + panic(err) + } + + for { + resp, err := client.Get("https://127.0.0.1:8443") + if err != nil { + panic(err) + } + b, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + panic(err) + } + + fmt.Printf("Server responded: %s\n", b) + time.Sleep(5 * time.Second) + } +} diff --git a/examples/basic-federation/pki/cloud/certs/intermediate_ca.crt b/examples/basic-federation/pki/cloud/certs/intermediate_ca.crt new file mode 100644 index 00000000..b2d002a4 --- /dev/null +++ b/examples/basic-federation/pki/cloud/certs/intermediate_ca.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBvjCCAWSgAwIBAgIQPDSG4MCReDzPu96+Cb5e0TAKBggqhkjOPQQDAjApMScw +JQYDVQQDEx5TbWFsbHN0ZXAgUHVibGljIENsb3VkIFJvb3QgQ0EwHhcNMTkwMTE4 +MjEwNjE2WhcNMjkwMTE1MjEwNjE2WjAxMS8wLQYDVQQDEyZTbWFsbHN0ZXAgUHVi +bGljIENsb3VkIEludGVybWVkaWF0ZSBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEH +A0IABCQRZefT8U34OiW3o+R2/Ob2DUWrcL87jj9D7IGtAgOjulbfoJaH3rnJumG2 +DtMImBJ1hPa2mXMjThnjOXSlGA+jZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMB +Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBSCHPvFHHqEJU82OtFPZVHhstA/rDAfBgNV +HSMEGDAWgBSMOU1vYot1qfDaTG2uY9l2nQNSADAKBggqhkjOPQQDAgNIADBFAiEA +hojptJQvmTlu9Ybyr9UCL6Akiks8U1RPF2NS+YKZm+8CIDjbipMuz5AXCez57/5r +ZrEv0JxcWpK6AxfitwyYg34e +-----END CERTIFICATE----- diff --git a/examples/basic-federation/pki/cloud/certs/kubernetes_root_ca.crt b/examples/basic-federation/pki/cloud/certs/kubernetes_root_ca.crt new file mode 100644 index 00000000..ce41b0d1 --- /dev/null +++ b/examples/basic-federation/pki/cloud/certs/kubernetes_root_ca.crt @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBkjCCATigAwIBAgIRAKqKZhDGVx8dcxTDGpowzNEwCgYIKoZIzj0EAwIwJzEl +MCMGA1UEAxMcU21hbGxzdGVwIEt1YmVybmV0ZXMgUm9vdCBDQTAeFw0xOTAxMTgy +MTA2NDdaFw0yOTAxMTUyMTA2NDdaMCcxJTAjBgNVBAMTHFNtYWxsc3RlcCBLdWJl +cm5ldGVzIFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASst212A8a9 +h1DBFEzCgIaoZEWWf0JlBkSmnlHCHZLK2ookNKY6k8UAki4o1xpYjeLtlL4xn4WL +mMEafC2tPQvxo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB +ATAdBgNVHQ4EFgQU1+ia0R8GNWYXgs7qkbXHzinghlEwCgYIKoZIzj0EAwIDSAAw +RQIgDQlbDQxnNxRsR8d/lQiBSy6v0u6BOmftfbB3y0CcGI4CIQC2dxkUvi6GsfHs +zRgU5ZPIT7sVEfNi9G3GZABj0vOnvQ== +-----END CERTIFICATE----- diff --git a/examples/basic-federation/pki/cloud/certs/root_ca.crt b/examples/basic-federation/pki/cloud/certs/root_ca.crt new file mode 100644 index 00000000..4c01727b --- /dev/null +++ b/examples/basic-federation/pki/cloud/certs/root_ca.crt @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBlTCCATygAwIBAgIRAPykhdlDneUGU9rI1g+Y40MwCgYIKoZIzj0EAwIwKTEn +MCUGA1UEAxMeU21hbGxzdGVwIFB1YmxpYyBDbG91ZCBSb290IENBMB4XDTE5MDEx +ODIxMDYxM1oXDTI5MDExNTIxMDYxM1owKTEnMCUGA1UEAxMeU21hbGxzdGVwIFB1 +YmxpYyBDbG91ZCBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESc9z +Y77gf4XhCCOzsAhvMThV3Wro6EVnfBaSlmmnq15VaONG6FP7kVyJEM+XD75Thu10 +AsxwB0w4WxKIJ63TNaNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB +Af8CAQEwHQYDVR0OBBYEFIw5TW9ii3Wp8NpMba5j2XadA1IAMAoGCCqGSM49BAMC +A0cAMEQCICVylyEZfBBilwKN1nvS4j9Lbt6/nhF5DH9K/wjPIBhiAiBZojDvMZhj +mreuuFfRC4kWE/OUG5Iz2qVUtlvL/NaXXQ== +-----END CERTIFICATE----- diff --git a/examples/basic-federation/pki/cloud/config/ca.federated.json b/examples/basic-federation/pki/cloud/config/ca.federated.json new file mode 100644 index 00000000..25577b78 --- /dev/null +++ b/examples/basic-federation/pki/cloud/config/ca.federated.json @@ -0,0 +1,40 @@ +{ + "root": "pki/cloud/certs/root_ca.crt", + "federatedRoots": ["pki/cloud/certs/kubernetes_root_ca.crt"], + "crt": "pki/cloud/certs/intermediate_ca.crt", + "key": "pki/cloud/secrets/intermediate_ca_key", + "address": ":1443", + "dnsNames": [ + "localhost" + ], + "logger": { + "format": "text" + }, + "authority": { + "provisioners": [ + { + "name": "sebastian@smallstep.com", + "type": "jwk", + "key": { + "use": "sig", + "kty": "EC", + "kid": "EE1ZiqkMaxsUdpz8SCSkRBzwK9TWUoidQnMnJ8Eryn8", + "crv": "P-256", + "alg": "ES256", + "x": "BcoXteWHdYxXUrckEQwEQDol2nM97J8KIg7GiXc3AMc", + "y": "8QkL41tl7BZ5uIf_VTOEypp8vsKUnDGpNdrfk0FNt0Q" + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoicTV2MkZ2bmRjNnF0ZWlEZkVBNWI5ZyJ9.MZCVUhU1yuYkhKbQqJDJX0Y6d1X6ranvIeGHIpWLc_STHAgta8c0tA.4o-sw0jTV064OtuL.QVqIo2l0Qf_MRXVghjFYUFkWlK-3VomqzskLLDfLz1norWQa-wEdV56_CIZ7gAPxiLj2N6VOlpEg-sKA2xL3w9b-2WovH_o93iN2MziiWajFf9uq-41LVyEeROd_6Gs4TQbxyz5rk_iMsZeRNRKTpYvW1E2lA4YlMTm4QLV7s7xkGaWsL_-pATfb24bnDMrjRyAVLR61rPHxUQ2wcK_hRG272xoSAsNOWRrUcnDYzjylj-YfmhQZy77Rf38Rxy3UlhB4iMB-y7wMoMuseRKTvBEncL-c0wrllKWUP_KjCl6VeanKWAGUilbmgIpEa1Y_QbNZTD9t0rw2TJSkjx0.CNtEZWZrfp542E65F2oi4w" + } + ] + }, + "tls": { + "cipherSuites": [ + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + ], + "minVersion": 1.2, + "maxVersion": 1.2, + "renegotiation": false + } +} \ No newline at end of file diff --git a/examples/basic-federation/pki/cloud/config/ca.json b/examples/basic-federation/pki/cloud/config/ca.json new file mode 100644 index 00000000..5da04e86 --- /dev/null +++ b/examples/basic-federation/pki/cloud/config/ca.json @@ -0,0 +1,40 @@ +{ + "root": "pki/cloud/certs/root_ca.crt", + "federatedRoots": [], + "crt": "pki/cloud/certs/intermediate_ca.crt", + "key": "pki/cloud/secrets/intermediate_ca_key", + "address": ":1443", + "dnsNames": [ + "localhost" + ], + "logger": { + "format": "text" + }, + "authority": { + "provisioners": [ + { + "name": "sebastian@smallstep.com", + "type": "jwk", + "key": { + "use": "sig", + "kty": "EC", + "kid": "EE1ZiqkMaxsUdpz8SCSkRBzwK9TWUoidQnMnJ8Eryn8", + "crv": "P-256", + "alg": "ES256", + "x": "BcoXteWHdYxXUrckEQwEQDol2nM97J8KIg7GiXc3AMc", + "y": "8QkL41tl7BZ5uIf_VTOEypp8vsKUnDGpNdrfk0FNt0Q" + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoicTV2MkZ2bmRjNnF0ZWlEZkVBNWI5ZyJ9.MZCVUhU1yuYkhKbQqJDJX0Y6d1X6ranvIeGHIpWLc_STHAgta8c0tA.4o-sw0jTV064OtuL.QVqIo2l0Qf_MRXVghjFYUFkWlK-3VomqzskLLDfLz1norWQa-wEdV56_CIZ7gAPxiLj2N6VOlpEg-sKA2xL3w9b-2WovH_o93iN2MziiWajFf9uq-41LVyEeROd_6Gs4TQbxyz5rk_iMsZeRNRKTpYvW1E2lA4YlMTm4QLV7s7xkGaWsL_-pATfb24bnDMrjRyAVLR61rPHxUQ2wcK_hRG272xoSAsNOWRrUcnDYzjylj-YfmhQZy77Rf38Rxy3UlhB4iMB-y7wMoMuseRKTvBEncL-c0wrllKWUP_KjCl6VeanKWAGUilbmgIpEa1Y_QbNZTD9t0rw2TJSkjx0.CNtEZWZrfp542E65F2oi4w" + } + ] + }, + "tls": { + "cipherSuites": [ + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + ], + "minVersion": 1.2, + "maxVersion": 1.2, + "renegotiation": false + } +} \ No newline at end of file diff --git a/examples/basic-federation/pki/cloud/secrets/intermediate_ca_key b/examples/basic-federation/pki/cloud/secrets/intermediate_ca_key new file mode 100644 index 00000000..ce4c563e --- /dev/null +++ b/examples/basic-federation/pki/cloud/secrets/intermediate_ca_key @@ -0,0 +1,8 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,61d1fda0c56e8b8fcf2eb8ba5e20903f + +pFdzP/NSsBCJ3LiVNd6Qg8BRZrNO9+MOcXeg93LAOFQVOswPRya+tfTojfv6t4Lm +qJYJlENAAKCjM5+GuMeslTpyqlgDvUYi36v4FAxvLNp49r+nzKXqq0chIPhlLwGb +Mr8rEtX97vosyYEtsYhbjjzgCJXMhBXzi9tbLkkiRxw= +-----END EC PRIVATE KEY----- diff --git a/examples/basic-federation/pki/cloud/secrets/root_ca_key b/examples/basic-federation/pki/cloud/secrets/root_ca_key new file mode 100644 index 00000000..87a6f13d --- /dev/null +++ b/examples/basic-federation/pki/cloud/secrets/root_ca_key @@ -0,0 +1,8 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,78223655d6ee4b458ff2d5b79dadbd06 + ++bHgP06x5ScVppDSysFN/1xVPnC5MrrUhG7zLG/eX6yJrj4YegthwnDrCuWSCc9U +0fv0jJ0QGGm8YL5NdH1EpOF7f3+KhOaCv3KLUFJqDWy7HC9anvLHRZPxEeGgndfZ +5EJz043Lg7xYSDDaH1a0ZVcHPpyiUJNhS9lxmOQP+Ec= +-----END EC PRIVATE KEY----- diff --git a/examples/basic-federation/pki/kubernetes/certs/cloud_root_ca.crt b/examples/basic-federation/pki/kubernetes/certs/cloud_root_ca.crt new file mode 100644 index 00000000..4c01727b --- /dev/null +++ b/examples/basic-federation/pki/kubernetes/certs/cloud_root_ca.crt @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBlTCCATygAwIBAgIRAPykhdlDneUGU9rI1g+Y40MwCgYIKoZIzj0EAwIwKTEn +MCUGA1UEAxMeU21hbGxzdGVwIFB1YmxpYyBDbG91ZCBSb290IENBMB4XDTE5MDEx +ODIxMDYxM1oXDTI5MDExNTIxMDYxM1owKTEnMCUGA1UEAxMeU21hbGxzdGVwIFB1 +YmxpYyBDbG91ZCBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESc9z +Y77gf4XhCCOzsAhvMThV3Wro6EVnfBaSlmmnq15VaONG6FP7kVyJEM+XD75Thu10 +AsxwB0w4WxKIJ63TNaNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB +Af8CAQEwHQYDVR0OBBYEFIw5TW9ii3Wp8NpMba5j2XadA1IAMAoGCCqGSM49BAMC +A0cAMEQCICVylyEZfBBilwKN1nvS4j9Lbt6/nhF5DH9K/wjPIBhiAiBZojDvMZhj +mreuuFfRC4kWE/OUG5Iz2qVUtlvL/NaXXQ== +-----END CERTIFICATE----- diff --git a/examples/basic-federation/pki/kubernetes/certs/intermediate_ca.crt b/examples/basic-federation/pki/kubernetes/certs/intermediate_ca.crt new file mode 100644 index 00000000..c3d14818 --- /dev/null +++ b/examples/basic-federation/pki/kubernetes/certs/intermediate_ca.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBuzCCAWGgAwIBAgIRAK/si8hkdtyDLAjg6ZiRxIgwCgYIKoZIzj0EAwIwJzEl +MCMGA1UEAxMcU21hbGxzdGVwIEt1YmVybmV0ZXMgUm9vdCBDQTAeFw0xOTAxMTgy +MTA2NDlaFw0yOTAxMTUyMTA2NDlaMC8xLTArBgNVBAMTJFNtYWxsc3RlcCBLdWJl +cm5ldGVzIEludGVybWVkaWF0ZSBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA +BBIuNImYDPC6BIGm0/C97su9GPsrGoS2uSHDuPIORbaGPtGI8A2SHInw7pHXRqnW +5TvrbCOcLI2Ao2RQvAd/9jCjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8E +CDAGAQH/AgEAMB0GA1UdDgQWBBT3w/Rtaw3B4mjhqwDb+/tCFLQTozAfBgNVHSME +GDAWgBTX6JrRHwY1ZheCzuqRtcfOKeCGUTAKBggqhkjOPQQDAgNIADBFAiEAz8Lo +GPyrFRGvQ6Eie/qIjJByNEmN3FCOJOJr0J7csy0CIBLxKfMhsT719con+/ZMBNRt +HEV9xTWpPhUvnlsTPIJl +-----END CERTIFICATE----- diff --git a/examples/basic-federation/pki/kubernetes/certs/root_ca.crt b/examples/basic-federation/pki/kubernetes/certs/root_ca.crt new file mode 100644 index 00000000..ce41b0d1 --- /dev/null +++ b/examples/basic-federation/pki/kubernetes/certs/root_ca.crt @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBkjCCATigAwIBAgIRAKqKZhDGVx8dcxTDGpowzNEwCgYIKoZIzj0EAwIwJzEl +MCMGA1UEAxMcU21hbGxzdGVwIEt1YmVybmV0ZXMgUm9vdCBDQTAeFw0xOTAxMTgy +MTA2NDdaFw0yOTAxMTUyMTA2NDdaMCcxJTAjBgNVBAMTHFNtYWxsc3RlcCBLdWJl +cm5ldGVzIFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASst212A8a9 +h1DBFEzCgIaoZEWWf0JlBkSmnlHCHZLK2ookNKY6k8UAki4o1xpYjeLtlL4xn4WL +mMEafC2tPQvxo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB +ATAdBgNVHQ4EFgQU1+ia0R8GNWYXgs7qkbXHzinghlEwCgYIKoZIzj0EAwIDSAAw +RQIgDQlbDQxnNxRsR8d/lQiBSy6v0u6BOmftfbB3y0CcGI4CIQC2dxkUvi6GsfHs +zRgU5ZPIT7sVEfNi9G3GZABj0vOnvQ== +-----END CERTIFICATE----- diff --git a/examples/basic-federation/pki/kubernetes/config/ca.federated.json b/examples/basic-federation/pki/kubernetes/config/ca.federated.json new file mode 100644 index 00000000..4f28c459 --- /dev/null +++ b/examples/basic-federation/pki/kubernetes/config/ca.federated.json @@ -0,0 +1,40 @@ +{ + "root": "pki/kubernetes/certs/root_ca.crt", + "federatedRoots": ["pki/kubernetes/certs/cloud_root_ca.crt"], + "crt": "pki/kubernetes/certs/intermediate_ca.crt", + "key": "pki/kubernetes/secrets/intermediate_ca_key", + "address": ":2443", + "dnsNames": [ + "localhost" + ], + "logger": { + "format": "text" + }, + "authority": { + "provisioners": [ + { + "name": "sebastian@smallstep.com", + "type": "jwk", + "key": { + "use": "sig", + "kty": "EC", + "kid": "S5gYgpeqcIAgc1Zr4myZXpgJ_Ao4ryS6F6wqg9o8RYo", + "crv": "P-256", + "alg": "ES256", + "x": "uYecJyfa3pKHrO36zVsPKCHAcCUoYKOic2M7_qv9Jes", + "y": "WXzgS-36_BcXSi-G86RcLmLaHJEjmcmkhzR9ajrhhGo" + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiRlBVMHBJclNYbUU5VzhFSzFaMlQ2USJ9.wTT9VpKIOKzoiaBJ2fIcOYwypkKTwuKauwkf4fcfmJ6_VVQ6TykIrA.y_YTjVhmpztcOqYq.9j_pppHHcJ3_VEbt-WfxSOks05QMXNI862uYWcFGc7EVCoD1qEiKIDKEuoUSTG-_WcgkaXrag9UUQPKfDpuYi6UJcyaLkehO2DBX26DJ1T-qEYlhPxPGpx8r7p84zcg_AftypD6PNheiCLe6HOQWWuPtuPrfyUpvyfMWkJC14NZjR4iJysKP5dndxFbSTI2XCw1X-zBDVD9xMnVPlRtezIIuDi2cLEYnNaIlr5NMNQBOrzQaSo1LQaOOoSa_OrZzTdjg7HaUU5DaAA6YEDQPfFxLIJdKshvj5sxDlH_LLY58mzsGECrUx396zjvN8FD-bFSrdbCNlJJ4xhtt34c.FhRAcFIg-5k2srdtdsq2VQ" + } + ] + }, + "tls": { + "cipherSuites": [ + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + ], + "minVersion": 1.2, + "maxVersion": 1.2, + "renegotiation": false + } +} \ No newline at end of file diff --git a/examples/basic-federation/pki/kubernetes/config/ca.json b/examples/basic-federation/pki/kubernetes/config/ca.json new file mode 100644 index 00000000..e4a55b68 --- /dev/null +++ b/examples/basic-federation/pki/kubernetes/config/ca.json @@ -0,0 +1,40 @@ +{ + "root": "pki/kubernetes/certs/root_ca.crt", + "federatedRoots": [], + "crt": "pki/kubernetes/certs/intermediate_ca.crt", + "key": "pki/kubernetes/secrets/intermediate_ca_key", + "address": ":2443", + "dnsNames": [ + "localhost" + ], + "logger": { + "format": "text" + }, + "authority": { + "provisioners": [ + { + "name": "sebastian@smallstep.com", + "type": "jwk", + "key": { + "use": "sig", + "kty": "EC", + "kid": "S5gYgpeqcIAgc1Zr4myZXpgJ_Ao4ryS6F6wqg9o8RYo", + "crv": "P-256", + "alg": "ES256", + "x": "uYecJyfa3pKHrO36zVsPKCHAcCUoYKOic2M7_qv9Jes", + "y": "WXzgS-36_BcXSi-G86RcLmLaHJEjmcmkhzR9ajrhhGo" + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiRlBVMHBJclNYbUU5VzhFSzFaMlQ2USJ9.wTT9VpKIOKzoiaBJ2fIcOYwypkKTwuKauwkf4fcfmJ6_VVQ6TykIrA.y_YTjVhmpztcOqYq.9j_pppHHcJ3_VEbt-WfxSOks05QMXNI862uYWcFGc7EVCoD1qEiKIDKEuoUSTG-_WcgkaXrag9UUQPKfDpuYi6UJcyaLkehO2DBX26DJ1T-qEYlhPxPGpx8r7p84zcg_AftypD6PNheiCLe6HOQWWuPtuPrfyUpvyfMWkJC14NZjR4iJysKP5dndxFbSTI2XCw1X-zBDVD9xMnVPlRtezIIuDi2cLEYnNaIlr5NMNQBOrzQaSo1LQaOOoSa_OrZzTdjg7HaUU5DaAA6YEDQPfFxLIJdKshvj5sxDlH_LLY58mzsGECrUx396zjvN8FD-bFSrdbCNlJJ4xhtt34c.FhRAcFIg-5k2srdtdsq2VQ" + } + ] + }, + "tls": { + "cipherSuites": [ + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + ], + "minVersion": 1.2, + "maxVersion": 1.2, + "renegotiation": false + } +} \ No newline at end of file diff --git a/examples/basic-federation/pki/kubernetes/secrets/intermediate_ca_key b/examples/basic-federation/pki/kubernetes/secrets/intermediate_ca_key new file mode 100644 index 00000000..6ae1afd6 --- /dev/null +++ b/examples/basic-federation/pki/kubernetes/secrets/intermediate_ca_key @@ -0,0 +1,8 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,fb0860a45dbae164b2657f27c2a3f1cf + +6nFswxVAct5zIqsThsJ1uYY6gzkhMzAmurih+mhlhANfl6SHURdzk8AtutIQrFfV +jr/vTPyr3aR+dqldt/wg1L9pJFc/OoWVlOFbltmLTkWMPk+VHKxR5V6A7IVYoKvm +EUFzVb+aHj6M9R7ecBf0IslGQ0nsqYa54WppGHmAA4A= +-----END EC PRIVATE KEY----- diff --git a/examples/basic-federation/pki/kubernetes/secrets/root_ca_key b/examples/basic-federation/pki/kubernetes/secrets/root_ca_key new file mode 100644 index 00000000..b8f030bb --- /dev/null +++ b/examples/basic-federation/pki/kubernetes/secrets/root_ca_key @@ -0,0 +1,8 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,965ede7ef96d4640932c18bdf1795645 + +treDpMX0uYFlWMiPvjYfnv6K9jmT4f8pTG6AkzZB0eeaNj04tt4FuIgrabHoZFNx +IC1mFIRZvhJaiOXNIvQbo/Wnweu8nVV/xn73xNKBramgfXDo9WCvIsffjRg1xtsq +s3SuONddo4IdpmrG7iEZTkDe2IzSV5NYhGsKiwvDvaU= +-----END EC PRIVATE KEY----- diff --git a/examples/basic-federation/server/main.go b/examples/basic-federation/server/main.go new file mode 100644 index 00000000..4a95c6af --- /dev/null +++ b/examples/basic-federation/server/main.go @@ -0,0 +1,73 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "os" + "time" + + "github.com/smallstep/certificates/ca" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0]) + os.Exit(1) + } + + token := os.Args[1] + + // make sure to cancel the renew goroutine + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + srv, err := ca.BootstrapServer(ctx, token, &http.Server{ + Addr: ":8443", + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + name := "nobody" + issuer := "none" + if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { + name = r.TLS.PeerCertificates[0].Subject.CommonName + issuer = r.TLS.PeerCertificates[len(r.TLS.PeerCertificates)-1].Issuer.CommonName + } + + w.Write([]byte(fmt.Sprintf("Hello %s (cert issued by '%s') at %s", name, issuer, time.Now().UTC()))) + }), + }, ca.AddFederationToRootCAs(), ListTrustedRoots()) + if err != nil { + panic(err) + } + + fmt.Println("Listening on :8443 ...") + if err := srv.ListenAndServeTLS("", ""); err != nil { + panic(err) + } +} + +// ListTrustedRoots prints list of trusted roots for illustration purposes +func ListTrustedRoots() ca.TLSOption { + fn := func(ctx *ca.TLSOptionCtx) error { + certs, err := ctx.Client.Federation() + if err != nil { + return err + } + roots, err := ctx.Client.Roots() + if err != nil { + return err + } + + if len(certs.Certificates) > len(roots.Certificates) { + fmt.Println("Server is using federated root certificates") + } + for _, cert := range certs.Certificates { + fmt.Printf("Accepting certs anchored in %s\n", cert.Certificate.Subject) + } + + return nil + } + return func(ctx *ca.TLSOptionCtx) error { + ctx.OnRenewFunc = append(ctx.OnRenewFunc, fn) + return fn(ctx) + } +}