forked from TrueCloudLab/certificates
fix grammar in examples/README.md
This commit is contained in:
parent
b94a87708a
commit
baaff35818
1 changed files with 94 additions and 86 deletions
|
@ -2,12 +2,11 @@
|
||||||
|
|
||||||
## Basic client usage
|
## Basic client usage
|
||||||
|
|
||||||
The basic-client example shows the use of the most of the functioanlity of the
|
The basic-client example shows the functionality of the `ca.Client` type. The
|
||||||
`ca.Client`, those methods works as an SDK for integrating other services with
|
methods work as an SDK for integrating services with the Certificate Authority (CA).
|
||||||
the Certificate Authority (CA).
|
|
||||||
|
|
||||||
In [basic-client/client.go](/examples/basic-client/client.go) we first can see
|
In [basic-client/client.go](/examples/basic-client/client.go) we see
|
||||||
the initialization of the client:
|
the initialization of a client:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
client, err := ca.NewClient("https://localhost:9000", ca.WithRootSHA256("84a033e84196f73bd593fad7a63e509e57fd982f02084359c4e8c5c864efc27d"))
|
client, err := ca.NewClient("https://localhost:9000", ca.WithRootSHA256("84a033e84196f73bd593fad7a63e509e57fd982f02084359c4e8c5c864efc27d"))
|
||||||
|
@ -15,80 +14,79 @@ client, err := ca.NewClient("https://localhost:9000", ca.WithRootSHA256("84a033e
|
||||||
|
|
||||||
The previous code uses the CA address and the root certificate fingerprint.
|
The previous code uses the CA address and the root certificate fingerprint.
|
||||||
The CA url will be present in the token, and the root fingerprint can be present
|
The CA url will be present in the token, and the root fingerprint can be present
|
||||||
too if the `--root root_ca.crt` option is use in the creation of the token. If
|
too if the `--root root_ca.crt` option is used in the creation of the token. If
|
||||||
this is the case is simpler to rely in the token and use just:
|
the token does contain the root fingerprint then it is simpler to use:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
client, err := ca.Bootstrap(token)
|
client, err := ca.Bootstrap(token)
|
||||||
```
|
```
|
||||||
|
|
||||||
After the initialization there're examples of all the client methods, they are
|
After the initialization there are examples of all the client methods. These
|
||||||
just a convenient way to use the CA API endpoints. The first method `Health`
|
methods are a convenient way to use the CA API. The first method, `Health`,
|
||||||
returns the status of the CA server, on the first implementation if the server
|
returns the status of the CA server. If the server is up it will return
|
||||||
is up it will return just ok.
|
`{"status":"ok"}`.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
health, err := client.Health()
|
health, err := client.Health()
|
||||||
// Health is a struct created from the JSON response {"status": "ok"}
|
// Health is a struct created from the JSON response {"status": "ok"}
|
||||||
```
|
```
|
||||||
|
|
||||||
The next method `Root` is used to get and verify the root certificate. We will
|
The next method `Root` is used to get and verify the root certificate. We
|
||||||
pass a finger print, it will download the root certificate from the CA and it
|
pass a fingerprint and it downloads the root certificate from the CA and
|
||||||
will make sure that the fingerprint matches. This method uses an insecure HTTP
|
verifies that the fingerprint matches. This method uses an insecure HTTP
|
||||||
client as it might be used in the initialization of the client, but the response
|
client as it might be used in the initialization of the client, but the response
|
||||||
is considered secure because we have compared against the given digest.
|
is considered secure because we have compared against the expected digest.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
root, err := client.Root("84a033e84196f73bd593fad7a63e509e57fd982f02084359c4e8c5c864efc27d")
|
root, err := client.Root("84a033e84196f73bd593fad7a63e509e57fd982f02084359c4e8c5c864efc27d")
|
||||||
```
|
```
|
||||||
|
|
||||||
After Root we have the most important method `Sign`, this is used to sign a
|
Next we have the most important method; `Sign`. `Sign` will authorize and sign a
|
||||||
Certificate Signing Request that we provide. To secure this request we use
|
CSR (Certificate Signing Request) that we provide. To authorize this request we use
|
||||||
the one-time-token. You can build your own certificate request and add it in
|
a provisioning token issued by an authorized provisioner.
|
||||||
the `*api.SignRequest`, but the ca package contains a method that will create a
|
You can build your own certificate request and add it in
|
||||||
secure random key, and create the CSR based on the information in the token.
|
the `*api.SignRequest`, but our CA SDK contains a method that will generate a
|
||||||
|
secure random key and create a CSR - combining the key with the information
|
||||||
|
provided in the provisioning token.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Create a CSR from token and return the sign request, the private key and an
|
// Create a CSR from a token and return the SignRequest, the private key, and an
|
||||||
// error if something failed.
|
// error if something failed.
|
||||||
req, pk, err := ca.CreateSignRequest(token)
|
req, pk, err := ca.CreateSignRequest(token)
|
||||||
if err != nil { ... }
|
if err != nil { ... }
|
||||||
|
|
||||||
// Do the sign request and return the signed certificate
|
// Do the Sign request and return the signed certificate.
|
||||||
sign, err := client.Sign(req)
|
sign, err := client.Sign(req)
|
||||||
if err != nil { ... }
|
if err != nil { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
To renew the certificate we can use the `Renew` method, the certificate renewal
|
Next is the `Renew` method which is used to (you guessed it!) renew certificates.
|
||||||
relies on a mTLS connection with a previous certificate, so we will need to pass
|
Certificate renewal relies on a mTLS connection with using an existing certificate.
|
||||||
a transport with the previous certificate.
|
So, as input we will need to pass a transport with the current certificate.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Get a cancelable context to stop the renewal goroutines and timers.
|
// Get a cancelable context to stop the renewal goroutines and timers.
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
// Create a transport from with the sign response and the private key.
|
// Create a transport with the sign response and the private key.
|
||||||
tr, err := client.Transport(ctx, sign, pk)
|
tr, err := client.Transport(ctx, sign, pk)
|
||||||
if err != nil { ... }
|
if err != nil { ... }
|
||||||
// Renew the certificate and get the new ones.
|
// Renew the certificate. The return type is equivalent to the Sign method.
|
||||||
// The return type are equivalent to ones in the Sign method.
|
|
||||||
renew, err := client.Renew(tr)
|
renew, err := client.Renew(tr)
|
||||||
if err != nil { ... }
|
if err != nil { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
All the previous methods map with one endpoint in the CA API, but the API
|
The following methods are for inpsecting Provisioners.
|
||||||
provides a couple more that are used for creating the tokens. For those we have
|
One method that returns a list of provisioners or a the encrypted key of one provisioner.
|
||||||
a couple of methods, one that returns a list of provisioners and one that
|
|
||||||
returns the encrypted key of one provisioner.
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Without options it will return the first 20 provisioners
|
// Without options it will return the first 20 provisioners.
|
||||||
provisioners, err := client.Provisioners()
|
provisioners, err := client.Provisioners()
|
||||||
// We can also set a limit up to 100
|
// We can also set a limit up to 100.
|
||||||
provisioners, err := client.Provisioners(ca.WithProvisionerLimit(100))
|
provisioners, err := client.Provisioners(ca.WithProvisionerLimit(100))
|
||||||
// With a pagination cursor
|
// With a pagination cursor.
|
||||||
provisioners, err := client.Provisioners(ca.WithProvisionerCursor("1f18c1ecffe54770e9107ce7b39b39735"))
|
provisioners, err := client.Provisioners(ca.WithProvisionerCursor("1f18c1ecffe54770e9107ce7b39b39735"))
|
||||||
// Or combining both
|
// Or combine both.
|
||||||
provisioners, err := client.Provisioners(
|
provisioners, err := client.Provisioners(
|
||||||
ca.WithProvisionerCursor("1f18c1ecffe54770e9107ce7b39b39735"),
|
ca.WithProvisionerCursor("1f18c1ecffe54770e9107ce7b39b39735"),
|
||||||
ca.WithProvisionerLimit(100),
|
ca.WithProvisionerLimit(100),
|
||||||
|
@ -99,21 +97,21 @@ provisioners, err := client.Provisioners(
|
||||||
key, err := client.ProvisionerKey("DmAtZt2EhmZr_iTJJ387fr4Md2NbzMXGdXQNW1UWPXk")
|
key, err := client.ProvisionerKey("DmAtZt2EhmZr_iTJJ387fr4Md2NbzMXGdXQNW1UWPXk")
|
||||||
```
|
```
|
||||||
|
|
||||||
The example shows also the use of some helper methods used to get configured
|
The following example shows how to create a
|
||||||
tls.Config objects that can be injected in servers and clients. These methods,
|
tls.Config object that can be injected into servers and clients. By default these
|
||||||
are also configured to auto-renew the certificate once two thirds of the
|
methods will spin off Go routines that auto-renew a certificate once (approximately)
|
||||||
duration of the certificate has passed, approximately.
|
two thirds of the duration of the certificate has passed.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Get a cancelable context to stop the renewal goroutines and timers.
|
// Get a cancelable context to stop the renewal goroutines and timers.
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
// Get tls.Config for a server
|
// Get tls.Config for a server.
|
||||||
tlsConfig, err := client.GetServerTLSConfig(ctx, sign, pk)
|
tlsConfig, err := client.GetServerTLSConfig(ctx, sign, pk)
|
||||||
// Get tls.Config for a client
|
// Get tls.Config for a client.
|
||||||
tlsConfig, err := client.GetClientTLSConfig(ctx, sign, pk)
|
tlsConfig, err := client.GetClientTLSConfig(ctx, sign, pk)
|
||||||
// Get an http.Transport for a client, this can be used as a http.RoundTripper
|
// Get an http.Transport for a client; this can be used as a http.RoundTripper
|
||||||
// in an http.Client
|
// in an http.Client.
|
||||||
tr, err := client.Transport(ctx, sign, pk)
|
tr, err := client.Transport(ctx, sign, pk)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -124,7 +122,7 @@ certificates $ bin/step-ca examples/pki/config/ca.json
|
||||||
2018/11/02 18:29:25 Serving HTTPS on :9000 ...
|
2018/11/02 18:29:25 Serving HTTPS on :9000 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
And just run the client.go with a new token:
|
Then run client.go with a new token:
|
||||||
```sh
|
```sh
|
||||||
certificates $ export STEPPATH=examples/pki
|
certificates $ export STEPPATH=examples/pki
|
||||||
certificates $ export STEP_CA_URL=https://localhost:9000
|
certificates $ export STEP_CA_URL=https://localhost:9000
|
||||||
|
@ -133,17 +131,15 @@ certificates $ go run examples/basic-client/client.go $(step ca token client.sma
|
||||||
|
|
||||||
## Bootstrap Client & Server
|
## Bootstrap Client & Server
|
||||||
|
|
||||||
On this example we are going to see the Certificate Authority running, as well
|
In this example we are going run the CA alongside a simple Server using TLS and
|
||||||
as a simple Server using TLS and a simple client doing TLS requests to the
|
a simple client making TLS requests to the server.
|
||||||
server.
|
|
||||||
|
|
||||||
The examples directory already contains a sample pki configuration with the
|
The examples directory already contains a sample pki configuration with the
|
||||||
password `password` hardcoded, but you can create your own using `step ca init`.
|
password `password` hardcoded, but you can create your own using `step ca init`.
|
||||||
|
|
||||||
These examples show the use of other helper methods, they are simple ways to
|
These examples show the use of some other helper methods - simple ways to
|
||||||
create TLS configured http.Server and http.Client objects. The methods are
|
create TLS configured http.Server and http.Client objects. The methods are
|
||||||
`BootstrapServer`, `BootstrapServerWithMTLS` and `BootstrapClient` and they are
|
`BootstrapServer`, `BootstrapServerWithMTLS` and `BootstrapClient`.
|
||||||
used like:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Get a cancelable context to stop the renewal goroutines and timers.
|
// Get a cancelable context to stop the renewal goroutines and timers.
|
||||||
|
@ -187,17 +183,20 @@ if err != nil {
|
||||||
resp, err := client.Get("https://localhost:8443")
|
resp, err := client.Get("https://localhost:8443")
|
||||||
```
|
```
|
||||||
|
|
||||||
We will demonstrate the mTLS configuration if a different example, for this one
|
We will demonstrate the mTLS configuration in a different example. In this
|
||||||
we will only verify it if provided.
|
examplefor we will configure the server to only verify client certificates
|
||||||
|
if they are provided.
|
||||||
|
|
||||||
|
To being with let's start the Step CA:
|
||||||
|
|
||||||
To run the example first we will start the certificate authority:
|
|
||||||
```sh
|
```sh
|
||||||
certificates $ bin/step-ca examples/pki/config/ca.json
|
certificates $ bin/step-ca examples/pki/config/ca.json
|
||||||
2018/11/02 18:29:25 Serving HTTPS on :9000 ...
|
2018/11/02 18:29:25 Serving HTTPS on :9000 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
We will start the server and we will type `password` when step asks for the
|
Next we will start the bootstrap-server and enter `password` prompted for the
|
||||||
provisioner password:
|
provisioner password:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
certificates $ export STEPPATH=examples/pki
|
certificates $ export STEPPATH=examples/pki
|
||||||
certificates $ export STEP_CA_URL=https://localhost:9000
|
certificates $ export STEP_CA_URL=https://localhost:9000
|
||||||
|
@ -207,7 +206,8 @@ Please enter the password to decrypt the provisioner key:
|
||||||
Listening on :8443 ...
|
Listening on :8443 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
We try that using cURL with the system certificates it will return an error:
|
Let's try to cURL our new bootstrap server with the system certificates bundle
|
||||||
|
as our root. It should fail.
|
||||||
```
|
```
|
||||||
certificates $ curl https://localhost:8443
|
certificates $ curl https://localhost:8443
|
||||||
curl: (60) SSL certificate problem: unable to get local issuer certificate
|
curl: (60) SSL certificate problem: unable to get local issuer certificate
|
||||||
|
@ -226,16 +226,19 @@ If you'd like to turn off curl's verification of the certificate, use
|
||||||
HTTPS-proxy has similar options --proxy-cacert and --proxy-insecure.
|
HTTPS-proxy has similar options --proxy-cacert and --proxy-insecure.
|
||||||
```
|
```
|
||||||
|
|
||||||
But if we use the root certificate it will properly work:
|
Now lets use the root certificate generated for the Step PKI. It should work.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
certificates $ curl --cacert examples/pki/secrets/root_ca.crt https://localhost:8443
|
certificates $ curl --cacert examples/pki/secrets/root_ca.crt https://localhost:8443
|
||||||
Hello nobody at 2018-11-03 01:49:25.66912 +0000 UTC!!!
|
Hello nobody at 2018-11-03 01:49:25.66912 +0000 UTC!!!
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice that in the response we see `nobody`, this is because the server didn't
|
Notice that in the response we see `nobody`. This is because the server did not
|
||||||
detected a TLS client configuration.
|
detected a TLS client configuration.
|
||||||
|
|
||||||
But if we the client with the certificate name Mike we'll see:
|
But if we create a client with it's own certificate (generated by the Step CA),
|
||||||
|
we should see the Common Name of the client certificate:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
certificates $ export STEPPATH=examples/pki
|
certificates $ export STEPPATH=examples/pki
|
||||||
certificates $ export STEP_CA_URL=https://localhost:9000
|
certificates $ export STEP_CA_URL=https://localhost:9000
|
||||||
|
@ -250,17 +253,19 @@ Server responded: Hello Mike at 2018-11-03 01:52:54.682787 +0000 UTC!!!
|
||||||
|
|
||||||
## Bootstrap mTLS Client & Server
|
## Bootstrap mTLS Client & Server
|
||||||
|
|
||||||
This example demonstrates a stricter configuration of the bootstrap server, this
|
This example demonstrates a stricter configuration of the bootstrap-server. Here
|
||||||
one always requires a valid client certificate.
|
we configure the server to require mTLS (mutual TLS) with a valid client certificate.
|
||||||
|
|
||||||
|
As always, we begin by starting the CA:
|
||||||
|
|
||||||
As always, to run this example will require the Certificate Authority running:
|
|
||||||
```sh
|
```sh
|
||||||
certificates $ bin/step-ca examples/pki/config/ca.json
|
certificates $ bin/step-ca examples/pki/config/ca.json
|
||||||
2018/11/02 18:29:25 Serving HTTPS on :9000 ...
|
2018/11/02 18:29:25 Serving HTTPS on :9000 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
We will start the mTLS server and we will type `password` when step asks for the
|
Next we start the mTLS server and we enter `password` when prompted for the
|
||||||
provisioner password:
|
provisioner password:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
certificates $ export STEPPATH=examples/pki
|
certificates $ export STEPPATH=examples/pki
|
||||||
certificates $ export STEP_CA_URL=https://localhost:9000
|
certificates $ export STEP_CA_URL=https://localhost:9000
|
||||||
|
@ -270,13 +275,17 @@ Please enter the password to decrypt the provisioner key:
|
||||||
Listening on :8443 ...
|
Listening on :8443 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
For mTLS, curl and curl with the root certificate will fail:
|
Now that the server is configured to require mTLS cURL-ing should fail even
|
||||||
|
if we use the correct root certificate bundle.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
certificates $ curl --cacert examples/pki/secrets/root_ca.crt https://localhost:8443
|
certificates $ curl --cacert examples/pki/secrets/root_ca.crt https://localhost:8443
|
||||||
curl: (35) error:1401E412:SSL routines:CONNECT_CR_FINISHED:sslv3 alert bad certificate
|
curl: (35) error:1401E412:SSL routines:CONNECT_CR_FINISHED:sslv3 alert bad certificate
|
||||||
```
|
```
|
||||||
|
|
||||||
But if we the client with the certificate name Mike we'll see:
|
However, if we use our client (which requests a certificate from the Step CA
|
||||||
|
when it starts):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
certificates $ export STEPPATH=examples/pki
|
certificates $ export STEPPATH=examples/pki
|
||||||
certificates $ export STEP_CA_URL=https://localhost:9000
|
certificates $ export STEP_CA_URL=https://localhost:9000
|
||||||
|
@ -291,11 +300,11 @@ Server responded: Hello Mike at 2018-11-07 21:54:02.141578 +0000 UTC!!!
|
||||||
|
|
||||||
## Certificate rotation
|
## Certificate rotation
|
||||||
|
|
||||||
We can use the bootstrap-server to demonstrate the certificate rotation. We've
|
We can use the bootstrap-server to demonstrate certificate rotation. We've
|
||||||
added second provisioner to to the ca with the name of `mike@smallstep.com`,
|
added a second provisioner, named `mike@smallstep.com`, to the CA configuration.
|
||||||
this provisioner is configured with a default certificate duration of 2 minutes.
|
This provisioner is has a default certificate duration of 2 minutes.
|
||||||
If we run the server, and inspect the used certificate, we can verify how it
|
Let's run the server, and inspect the certificate. We can should be able to
|
||||||
rotates after approximately two thirds of the duration has passed.
|
see the certificate rotate once approximately 2/3rds of it's lifespan has passed.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
certificates $ export STEPPATH=examples/pki
|
certificates $ export STEPPATH=examples/pki
|
||||||
|
@ -306,9 +315,9 @@ Please enter the password to decrypt the provisioner key:
|
||||||
Listening on :8443 ...
|
Listening on :8443 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
In this specific case, the the rotation will happen after 74-80 seconds have
|
In this case, the certificate will rotate after 74-80 seconds.
|
||||||
passed, the exact formula is 120-120/3-rand(120/20), where rand will return a
|
The exact formula is `<duration>-<duration>/3-rand(<duration>/20)` (`duration=120`
|
||||||
number between 0 and 6.
|
in our example).
|
||||||
|
|
||||||
We can use the following command to check the certificate expiration and to make
|
We can use the following command to check the certificate expiration and to make
|
||||||
sure the certificate changes after 74-80 seconds.
|
sure the certificate changes after 74-80 seconds.
|
||||||
|
@ -319,21 +328,21 @@ certificates $ step certificate inspect --insecure https://localhost:8443
|
||||||
|
|
||||||
## NGINX with Step CA certificates
|
## NGINX with Step CA certificates
|
||||||
|
|
||||||
The example under the `docker` directory shows how to combine the Smallstep CA
|
The example under the `docker` directory shows how to combine the Step CA
|
||||||
with NGINX to server pages or proxy services using certificates created by the
|
with NGINX to serve or proxy services using certificates created by the
|
||||||
step-ca.
|
Step CA.
|
||||||
|
|
||||||
This example creates 3 different docker images:
|
This example creates 3 different docker images:
|
||||||
|
|
||||||
* nginx-test: docker image with NGINX and a script using inotify-tools to watch
|
* nginx-test: docker image with NGINX and a script using inotify-tools to watch
|
||||||
for changes in the certificate to reload NGINX.
|
for changes in the certificate to reload NGINX.
|
||||||
* step-ca-test: docker image with the Smallstep CA
|
* step-ca-test: docker image with the Step CA
|
||||||
* step-renewer-test: docker images with the step cli tool, it creates the
|
* step-renewer-test: docker image with the step cli tool - it creates the
|
||||||
certificate and has a cron that renews the certificate. Right now the cron
|
certificate and sets a cron that renews the certificate (the cron
|
||||||
runs every minute for testing purposes.
|
runs every minute for testing purposes).
|
||||||
|
|
||||||
To run this test you need to have docker daemon running. With docker running
|
To run this test you need to have the docker daemon running. With docker running
|
||||||
swith to the `examples/docker directory` and just run `make`
|
swith to the `examples/docker directory` and run `make`:
|
||||||
|
|
||||||
```
|
```
|
||||||
certificates $ cd examples/docker/
|
certificates $ cd examples/docker/
|
||||||
|
@ -370,7 +379,7 @@ make sure the cert is right we need to add the following entry to `/etc/hosts`:
|
||||||
127.0.0.1 nginx
|
127.0.0.1 nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
Now we can use curl to check:
|
Now we can use cURL to verify:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker $ curl --cacert ca/pki/secrets/root_ca.crt https://nginx:4443/
|
docker $ curl --cacert ca/pki/secrets/root_ca.crt https://nginx:4443/
|
||||||
|
@ -401,8 +410,7 @@ Commercial support is available at
|
||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
Now you can use `make inspect` to inspect the certificate to see how the
|
We can use `make inspect` to witness the certificate being rotated every minute.
|
||||||
certificate gets updated every minute:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker $ make inspect | head
|
docker $ make inspect | head
|
||||||
|
@ -429,7 +437,7 @@ Certificate:
|
||||||
Not After : Nov 11 02:14:00 2018 UTC
|
Not After : Nov 11 02:14:00 2018 UTC
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, to remove the containers and volumes you can use `make down`:
|
Finally, to cleanup the containers and volumes created in this demo use `make down`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker $ make down
|
docker $ make down
|
||||||
|
|
Loading…
Reference in a new issue