diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index c64bea4d..f08c1a06 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -379,6 +379,80 @@ $ bin/step ca provisioner remove jim@smallstep.com --all The same entity may have multiple provisioners for authorizing different types of certs. Each of these provisioners must have unique keys. +## Use Custom Claims for Provisioners to Control Certificate Validity etc + +It's possible to configure provisioners on the CA to issue certs using propoerties specific to their target environments. Most commonly different validity periods and disabling renewals for certs. Here's how: + +```bash +$ step ca init +# complete the init steps +$ step ca provisioner add --create dev@smallstep.com +# lets create a provisioner for dev certs +Please enter a password to encrypt the provisioner private key? password +# add claims inside a provisioner element in ~/.step/config/ca.json +~/.step/config/ca.json +[...] +"authority": { + "provisioners": [ + { + "name": "you@smallstep.com", + "type": "jwk", + "key": { + "use": "sig", + "kty": "EC", + "kid": "Kg43gSukHnl8f5NztLPDxqpz_9TNUILnMrIMIa70jOU", + "crv": "P-256", + "alg": "ES256", + "x": "So0JVWFFXo-6GmDwq6WWZZk-AFZt5GKTx5PzdLhdsrQ", + "y": "kVz8pCl2Qx9fZmJZhXGrHpufwNDTp7oHwi8Zaj7rhiQ" + }, + "encryptedKey": "...", ++ "claims": { ++ "minTLSCertDuration": "5s", ++ "maxTLSCertDuration": "12h", ++ "defaultTLSCertDuration": "2h", ++ "disableRenewal": true ++ } + } + ] +}, +[...] + +# launch CA... +$ step-ca $(step path)/config/ca.json +Please enter the password to decrypt ~/.step/secrets/intermediate_ca_key: password +2019/02/21 12:09:51 Serving HTTPS on :9443 ... +``` + +Please [`step ca provisioner`](https://smallstep.com/docs/cli/ca/provisioner/)'s docs for details on all available claims properties. The durations are strings which are a sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + +Now certs issued by the `dev@smallstep.com` provisioner will be valid for two hours and deny renewals. Command line flags allow validity extension up to 12h, please see [`step ca certificate`](https://smallstep.com/docs/cli/ca/certificate/)'s docs for details. + +```bash +# grab a cert, will also work with 'step ca token' flow +$ step ca certificate localhost site.crt site.key +Use the arrow keys to navigate: ↓ ↑ → ← +What provisioner key do you want to use? + IY7gYg_cDKmXtcs1sbhdBDDb9K9YvLO5aHzArjaayso (sebastian@smallstep.com) + ▸ uBYWYDCpeJu_IYzMGPZ1LJJTdlaiJQfdpkOVewbjy-8 (dev@smallstep.com) + +✔ Please enter the password to decrypt the provisioner key: password +✔ CA: https://ca.smallstep.com:9443/1.0/sign +✔ Certificate: site.crt +✔ Private Key: site.key + +$ step certificate inspect site.crt --format json | jq .validity +{ + "start": "2019-02-21T20:19:06Z", + "end": "2019-02-21T22:19:06Z", + "length": 7200 +} + +# renewals will be denied for certs issued by this provisioner +$ step ca renew site.crt site.key +error renewing certificate: Unauthorized +``` + ## Notes on Securing the Step CA and your PKI. In this section we recommend a few best practices when it comes to diff --git a/examples/README.md b/examples/README.md index f6527db3..a2323302 100644 --- a/examples/README.md +++ b/examples/README.md @@ -555,6 +555,69 @@ Hello kube_client (cert issued by 'Smallstep Kubernetes Root CA') at 2019-01-28 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. +## Custom certificate validity periods using Custom Claims + +Bring up the certificate authority with the example: + +```sh +certificates $ step-ca examples/pki/config/ca.json +2019/03/11 13:37:03 Serving HTTPS on :9000 ... +``` + +The example comes with multiple provisioner options, two of which have custom claims to expand the validity of certificates: + +```sh +$ step ca provisioner list | jq '.[] | "\(.name): \(.claims.defaultTLSCertDuration)"' +# null means step default of 24h for cert validity +"mariano@smallstep.com: null" +"mike@smallstep.com: 2m0s" +"decade: 87600h0m0s" +"90days: 2160h0m0s" +``` + +A closer look at a duration-bound provisioner, `90days` for instance, reveals the custom configuration for certificate validity. + +```sh +$ step ca provisioner list | jq '.[3].claims' +{ + "maxTLSCertDuration": "2160h0m0s", + "defaultTLSCertDuration": "2160h0m0s" +} +``` + +Certificates with different validity periods can be generated using the respective provisioners. +The durations are strings which are a sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + +Please see [Getting Started](https://github.com/smallstep/certificates/blob/master/docs/GETTING_STARTED.md) in the docs directory to learn what custom claims configuration options are available and how to use them. + +```sh +$ step ca certificate decade decade.crt decade.key +✔ Key ID: iu7VZxKUcquv1BCWuvEUOyRy4zYyCmgt61OpRW5VbRE (decade) +✔ Please enter the password to decrypt the provisioner key: password +✔ CA: https://localhost:9000/1.0/sign +✔ Certificate: decade.crt +✔ Private Key: decade.key +$ step certificate inspect --format json decade.crt | jq .validity +{ + "start": "2019-03-11T22:34:30Z", + "end": "2029-03-08T22:34:30Z", + "length": 315360000 +} + +$ step ca certificate 90days 90days.crt 90days.key +✔ Key ID: 2LgjIvfirblnFMC6FjUr8jYkO8nOqz4rKoarCc8kiGU (90days) +✔ Please enter the password to decrypt the provisioner key: password +✔ CA: https://localhost:9000/1.0/sign +✔ Certificate: 90days.crt +✔ Private Key: 90days.key +$ step certificate inspect --format json 90days.crt | jq .validity +{ + "start": "2019-03-11T22:35:39Z", + "end": "2019-06-09T22:35:39Z", + "length": 7776000 +} +``` + ## Configuration Management Tools Configuration management tools such as Puppet, Chef, Ansible, Salt, etc. make diff --git a/examples/pki/config/ca.json b/examples/pki/config/ca.json index 193e140c..2249b5fb 100644 --- a/examples/pki/config/ca.json +++ b/examples/pki/config/ca.json @@ -1,58 +1,95 @@ { - "root": "examples/pki/secrets/root_ca.crt", - "crt": "examples/pki/secrets/intermediate_ca.crt", - "key": "examples/pki/secrets/intermediate_ca_key", - "password": "password", - "address": ":9000", - "dnsNames": [ - "localhost" - ], - "logger": { - "format": "text" - }, - "authority": { - "provisioners": [ - { - "name": "mariano@smallstep.com", - "type": "jwk", - "key": { - "use": "sig", - "kty": "EC", - "kid": "DmAtZt2EhmZr_iTJJ387fr4Md2NbzMXGdXQNW1UWPXk", - "crv": "P-256", - "alg": "ES256", - "x": "jXoO1j4CXxoTC32pNzkVC8l6k2LfP0k5ndhJZmcdVbk", - "y": "c3JDL4GTFxJWHa8EaHdMh4QgwMh64P2_AGWrD0ADXcI" + "root": "examples/pki/secrets/root_ca.crt", + "federatedRoots": null, + "crt": "examples/pki/secrets/intermediate_ca.crt", + "key": "examples/pki/secrets/intermediate_ca_key", + "address": ":9000", + "dnsNames": [ + "localhost" + ], + "logger": { + "format": "text" + }, + "authority": { + "provisioners": [ + { + "type": "jwk", + "name": "mariano@smallstep.com", + "key": { + "use": "sig", + "kty": "EC", + "kid": "DmAtZt2EhmZr_iTJJ387fr4Md2NbzMXGdXQNW1UWPXk", + "crv": "P-256", + "alg": "ES256", + "x": "jXoO1j4CXxoTC32pNzkVC8l6k2LfP0k5ndhJZmcdVbk", + "y": "c3JDL4GTFxJWHa8EaHdMh4QgwMh64P2_AGWrD0ADXcI" + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiOTFVWjdzRGw3RlNXcldfX1I1NUh3USJ9.FcWtrBDNgrkA33G9Ll9sXh1cPF-3jVXeYe1FLmSDc_Q2PmfLOPvJOA.0ZoN32ayaRWnufJb.WrkffMmDLWiq1-2kn-w7-kVBGW12gjNCBHNHB1hyEdED0rWH1YWpKd8FjoOACdJyLhSn4kAS3Lw5AH7fvO27A48zzvoxZU5EgSm5HG9IjkIH-LBJ-v79ShkpmPylchgjkFhxa5epD11OIK4rFmI7s-0BCjmJokLR_DZBhDMw2khGnsr_MEOfAz9UnqXaQ4MIy8eT52xUpx68gpWFlz2YP3EqiYyNEv0PpjMtyP5lO2i8-p8BqvuJdus9H3fO5Dg-1KVto1wuqh4BQ2JKTauv60QAnM_4sdxRHku3F_nV64SCrZfDvnN2ve21raFROtyXaqHZhN6lyoPxDncy8v4.biaOblEe0N-gMpJyFZ-3-A" + }, + { + "type": "jwk", + "name": "mike@smallstep.com", + "key": { + "use": "sig", + "kty": "EC", + "kid": "YYNxZ0rq0WsT2MlqLCWvgme3jszkmt99KjoGEJJwAKs", + "crv": "P-256", + "alg": "ES256", + "x": "LsI8nHBflc-mrCbRqhl8d3hSl5sYuSM1AbXBmRfznyg", + "y": "F99LoOvi7z-ZkumsgoHIhodP8q9brXe4bhF3szK-c_w" + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiVERQS2dzcEItTUR4ZDJxTGo0VlpwdyJ9.2_j0cZgTm2eFkZ-hrtr1hBIvLxN0w3TZhbX0Jrrq7vBMaywhgFcGTA.mCasZCbZJ-JT7vjA.bW052WDKSf_ueEXq1dyxLq0n3qXWRO-LXr7OzBLdUKWKSBGQrzqS5KJWqdUCPoMIHTqpwYvm-iD6uFlcxKBYxnsAG_hoq_V3icvvwNQQSd_q7Thxr2_KtPIDJWNuX1t5qXp11hkgb-8d5HO93CmN7xNDG89pzSUepT6RYXOZ483mP5fre9qzkfnrjx3oPROCnf3SnIVUvqk7fwfXuniNsg3NrNqncHYUQNReiq3e9I1R60w0ZQTvIReY7-zfiq7iPgVqmu5I7XGgFK4iBv0L7UOEora65b4hRWeLxg5t7OCfUqrS9yxAk8FdjFb9sEfjopWViPRepB0dYPH8dVI.fb6-7XWqp0j6CR9Li0NI-Q", + "claims": { + "minTLSCertDuration": "1m0s", + "defaultTLSCertDuration": "2m0s" + } + }, + { + "type": "jwk", + "name": "decade", + "key": { + "use": "sig", + "kty": "EC", + "kid": "iu7VZxKUcquv1BCWuvEUOyRy4zYyCmgt61OpRW5VbRE", + "crv": "P-256", + "alg": "ES256", + "x": "PExnlmHxnnfpvp4bznMKbA6L_9Bk9ZhtsmvbOwh9Kys", + "y": "rrMPGvxscRzDdOYtZ1wsxeQjuuFl0nSzkwTHV_P-K-Y" }, - "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiOTFVWjdzRGw3RlNXcldfX1I1NUh3USJ9.FcWtrBDNgrkA33G9Ll9sXh1cPF-3jVXeYe1FLmSDc_Q2PmfLOPvJOA.0ZoN32ayaRWnufJb.WrkffMmDLWiq1-2kn-w7-kVBGW12gjNCBHNHB1hyEdED0rWH1YWpKd8FjoOACdJyLhSn4kAS3Lw5AH7fvO27A48zzvoxZU5EgSm5HG9IjkIH-LBJ-v79ShkpmPylchgjkFhxa5epD11OIK4rFmI7s-0BCjmJokLR_DZBhDMw2khGnsr_MEOfAz9UnqXaQ4MIy8eT52xUpx68gpWFlz2YP3EqiYyNEv0PpjMtyP5lO2i8-p8BqvuJdus9H3fO5Dg-1KVto1wuqh4BQ2JKTauv60QAnM_4sdxRHku3F_nV64SCrZfDvnN2ve21raFROtyXaqHZhN6lyoPxDncy8v4.biaOblEe0N-gMpJyFZ-3-A" - }, - { - "name": "mike@smallstep.com", - "type": "jwk", - "key": { - "use": "sig", - "kty": "EC", - "kid": "YYNxZ0rq0WsT2MlqLCWvgme3jszkmt99KjoGEJJwAKs", - "crv": "P-256", - "alg": "ES256", - "x": "LsI8nHBflc-mrCbRqhl8d3hSl5sYuSM1AbXBmRfznyg", - "y": "F99LoOvi7z-ZkumsgoHIhodP8q9brXe4bhF3szK-c_w" - }, - "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiVERQS2dzcEItTUR4ZDJxTGo0VlpwdyJ9.2_j0cZgTm2eFkZ-hrtr1hBIvLxN0w3TZhbX0Jrrq7vBMaywhgFcGTA.mCasZCbZJ-JT7vjA.bW052WDKSf_ueEXq1dyxLq0n3qXWRO-LXr7OzBLdUKWKSBGQrzqS5KJWqdUCPoMIHTqpwYvm-iD6uFlcxKBYxnsAG_hoq_V3icvvwNQQSd_q7Thxr2_KtPIDJWNuX1t5qXp11hkgb-8d5HO93CmN7xNDG89pzSUepT6RYXOZ483mP5fre9qzkfnrjx3oPROCnf3SnIVUvqk7fwfXuniNsg3NrNqncHYUQNReiq3e9I1R60w0ZQTvIReY7-zfiq7iPgVqmu5I7XGgFK4iBv0L7UOEora65b4hRWeLxg5t7OCfUqrS9yxAk8FdjFb9sEfjopWViPRepB0dYPH8dVI.fb6-7XWqp0j6CR9Li0NI-Q", "claims": { - "minTLSCertDuration": "60s", - "defaultTLSCertDuration": "120s" - } - } - ] - }, - "tls": { - "cipherSuites": [ - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" - ], - "minVersion": 1.2, - "maxVersion": 1.2, - "renegotiation": false - } -} \ No newline at end of file + "maxTLSCertDuration": "87600h", + "defaultTLSCertDuration": "87600h" + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiZS1OVzRaZlBUNjFCUmR1bjJyNk9OZyJ9.zjToJ_Od6RIzVmo0cnmLZ69am410ftfBW594qNt60KmKX6JEWUufhA.kSrC74fKK3CkqiNS.G-oUqQhYMFIKuSj8thg9B5TeiaIMsQ-o_PTxIZE-Qb8TDU15ehPAsuIQmnbM6dSpkSGCmZgHTscp3xgLyv6QEBBjUHBpLwciWyipj1KBZDKSgLKeV6G2NiVBMETOaD1DsX3DxrHM-K3T1chXJFMJfkDSx1OEtaVfzqVYLyvNb5y_26oeRNSNYuTLzOrk6Ebr6KJE6lSWpvu1dtOrDAhTErouC56EQu2fTeDCa9eN50iRs4OjmF6FtBlR63h6FkvbmjJWC3zbIOe2RXRQx0Po6_dnKXSIqs7JMZSBerlgw6jzHme8YvqBqc2Ccy4Y4gJ23nwLkcsOVuFNdk6Nb7s.SB296DDrS-Wi4a9x_TGv4A" + }, + { + "type": "jwk", + "name": "90days", + "key": { + "use": "sig", + "kty": "EC", + "kid": "2LgjIvfirblnFMC6FjUr8jYkO8nOqz4rKoarCc8kiGU", + "crv": "P-256", + "alg": "ES256", + "x": "iHFHMN91iFUDLh2LweFj6o0gDJ-pdmBY4IFIBNfUqd4", + "y": "Yfym7KtzZQaQc1gQoT81ggNBPvAdV_0CW0A5mQgOsOc" + }, + "claims": { + "maxTLSCertDuration": "2160h", + "defaultTLSCertDuration": "2160h" + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiYk9XV0ZUN29uZldtZTdvbzdCMFZOdyJ9.p3gs2xd-Bdtwz1WGzQUZrcZeA8mpaMn_R_wTInpzZ9G1vIeRk-9T4g.RQNXmZP8uAzF1n8b.WpLqmNV_I0RIetdID2ag-igZryM8ekSimaHrXKoEpRAlBdBDZC-9qkbrJPNcTPRUi-29iZiBxKQ-0GX7ytiyulrQl7UfxUSrtT5vjhJEthSOGYXAOerUAnodGjpLCtIueTwVl6KJA2bXUapUd9xFn3DXfVgFagwqo1MrXKuIR0R5A4sjmEx8d2Kn_KQr0ZNnSOaAod2os4tmh3A87u9Jb51FMxhP-8Qbn7ff-RXwT_015C64Ux1zzS-ok89XbTgyfGxkah0-fVFAgS0zosHLI3C_pvumcglmFXZz7otH596BAU_QkqME6X-PGte6j6eldFobP_96tBxOhIRgVKw.Ky4xLbQZEGaBPjGJnKurng" + } + ] + }, + "tls": { + "cipherSuites": [ + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + ], + "minVersion": 1.2, + "maxVersion": 1.2, + "renegotiation": false + }, + "password": "password" +}