From 7b1f4a43cf0c47904360eb8ae015269902b014be Mon Sep 17 00:00:00 2001
From: Sebastian Tiedtke <sebastiantiedtke@gmail.com>
Date: Fri, 22 Mar 2019 12:16:56 -0700
Subject: [PATCH] Added example for custom claims (#39)

Add docs and examples for custom claims
---
 docs/GETTING_STARTED.md     |  74 ++++++++++++++++++
 examples/README.md          |  63 ++++++++++++++++
 examples/pki/config/ca.json | 145 ++++++++++++++++++++++--------------
 3 files changed, 228 insertions(+), 54 deletions(-)

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"
+                "claims": {
+                    "maxTLSCertDuration": "87600h",
+                    "defaultTLSCertDuration": "87600h"
                 },
-                "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiVERQS2dzcEItTUR4ZDJxTGo0VlpwdyJ9.2_j0cZgTm2eFkZ-hrtr1hBIvLxN0w3TZhbX0Jrrq7vBMaywhgFcGTA.mCasZCbZJ-JT7vjA.bW052WDKSf_ueEXq1dyxLq0n3qXWRO-LXr7OzBLdUKWKSBGQrzqS5KJWqdUCPoMIHTqpwYvm-iD6uFlcxKBYxnsAG_hoq_V3icvvwNQQSd_q7Thxr2_KtPIDJWNuX1t5qXp11hkgb-8d5HO93CmN7xNDG89pzSUepT6RYXOZ483mP5fre9qzkfnrjx3oPROCnf3SnIVUvqk7fwfXuniNsg3NrNqncHYUQNReiq3e9I1R60w0ZQTvIReY7-zfiq7iPgVqmu5I7XGgFK4iBv0L7UOEora65b4hRWeLxg5t7OCfUqrS9yxAk8FdjFb9sEfjopWViPRepB0dYPH8dVI.fb6-7XWqp0j6CR9Li0NI-Q",
+				"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": {
-                    "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": "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"
+}
-- 
GitLab