cert-manager/docs/tutorials/quick-start/index.rst
davegrix a72b935a96 Update index.rst
Updated to fix error

Signed-off-by: Dave Grix <herghostuk@gmail.com>
2018-12-05 09:10:23 +00:00

727 lines
26 KiB
ReStructuredText

=================================================
Quick-Start using Cert-Manager with NGINX Ingress
=================================================
Step 0 - Install Helm Client
=============================
**Skip this section if you have helm installed.**
The easiest way to install `cert-manager` is to use `Helm`_, a templating and
deployment tool for Kubernetes resources.
First, ensure the Helm client is installed following the
`Helm installation instructions`_.
For example, on macOS:
.. code-block:: shell
$ brew install kubernetes-helm
.. _`Helm`: https://helm.sh
.. _`Helm installation instructions`: https://github.com/kubernetes/helm/blob/master/docs/install.md
Step 1 - Installer Tiller
=========================
**Skip this section if you have Tiller set-up.**
Tiller is Helm's server-side component, which the ``helm`` client uses to
deploy resources.
Deploying resources is a privileged operation; in the general case requiring
arbitrary privileges. With this example, we give Tiller complete control
of the cluster. View the documentation on `securing helm`_ for details on
setting up appropriate permissions for your environment.
.. _`securing helm`: https://docs.helm.sh/using_helm/#securing-your-helm-installation
Create the a ServiceAccount for tiller:
.. code-block:: shell
$ kubectl create serviceaccount tiller --namespace=kube-system
serviceaccount "tiller" created
Grant the ``tiller`` service account cluster admin privileges:
.. code-block:: shell
$ kubectl create clusterrolebinding tiller-admin --serviceaccount=kube-system:tiller --clusterrole=cluster-admin
clusterrolebinding.rbac.authorization.k8s.io "tiller-admin" created
Install tiller with the ``tiller`` service account:
.. code-block:: shell
$ helm init --service-account=tiller
$HELM_HOME has been configured at /Users/myaccount/.helm.
Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
To prevent this, run `helm init` with the --tiller-tls-verify flag.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
Happy Helming!
Update the helm repository with the latest charts:
.. code-block:: shell
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "stable" chart repository
...Successfully got an update from the "coreos" chart repository
Update Complete. ⎈ Happy Helming!⎈
Step 2 - Deploy the NGINX Ingress Controller
============================================
A `kubernetes ingress controller`_ is designed to be the access point for
HTTP and HTTPS traffic to the software running within your cluster. The
nginx-ingress controller does this by providing an HTTP proxy service
supported by your cloud provider's load balancer.
You can get more details about nginx-ingress and how it works from the
`documentation for nginx-ingress`_.
.. _`kubernetes ingress controller`: https://kubernetes.io/docs/concepts/services-networking/ingress/
.. _`documentation for nginx-ingress`: https://kubernetes.github.io/ingress-nginx/
Use ``helm`` to install an Nginx Ingress controller:
.. code-block:: shell
$ helm install stable/nginx-ingress --name quickstart
NAME: quickstart
LAST DEPLOYED: Sat Nov 10 10:25:06 2018
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME AGE
quickstart-nginx-ingress-controller 0s
==> v1beta1/ClusterRole
quickstart-nginx-ingress 0s
==> v1beta1/Deployment
quickstart-nginx-ingress-controller 0s
quickstart-nginx-ingress-default-backend 0s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
quickstart-nginx-ingress-controller-6cfc45747-wcxrg 0/1 ContainerCreating 0 0s
quickstart-nginx-ingress-default-backend-bf9db5c67-dkg4l 0/1 ContainerCreating 0 0s
==> v1/ServiceAccount
NAME AGE
quickstart-nginx-ingress 0s
==> v1beta1/ClusterRoleBinding
quickstart-nginx-ingress 0s
==> v1beta1/Role
quickstart-nginx-ingress 0s
==> v1beta1/RoleBinding
quickstart-nginx-ingress 0s
==> v1/Service
quickstart-nginx-ingress-controller 0s
quickstart-nginx-ingress-default-backend 0s
NOTES:
The nginx-ingress controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace default get services -o wide -w quickstart-nginx-ingress-controller'
An example Ingress that makes use of the controller:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: example
namespace: foo
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: exampleService
servicePort: 80
path: /
# This section is only required if TLS is to be enabled for the Ingress
tls:
- hosts:
- www.example.com
secretName: example-tls
If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:
apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
type: kubernetes.io/tls
It can take a minute or two for the cloud provider to provide and link a public
IP address. When it is complete, you can see the external IP address using the
``kubectl`` command:
.. code-block:: shell
:emphasize-lines: 4
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.63.240.1 <none> 443/TCP 23m
quickstart-nginx-ingress-controller LoadBalancer 10.63.248.177 35.233.154.161 80:31345/TCP,443:31376/TCP 16m
quickstart-nginx-ingress-default-backend ClusterIP 10.63.250.234 <none> 80/TCP 16m
This command shows you all the services in your cluster (in the ``default``
namespace), and any external IP addresses they have. When you first create the
controller, your cloud provider won't have assigned and allocated an IP address
through the LoadBalancer yet. Until it does, the external IP address for the
service will be listed as ``<pending>``.
Your cloud provider may have options for reserving an IP address prior to
creating the ingress controller and using that IP address rather than assigning
an IP address from a pool. Read through the documentation from your cloud
provider on how to arrange that.
Step 3 - Assign a DNS name
==========================
The external IP that is allocated to the ingress-controller is the IP to which
all incoming traffic should be routed. To enable this, add it to a DNS zone you
control, for example as `example.your-domain.com`.
This quickstart assumes you know how to assign a DNS entry to an IP address and
will do so.
Step 4 - Deploy an Example Service
==================================
Your service may have its own chart, or you may be deploying it directly with
manifests. This quickstart uses manifests to create and expose a sample
service. The example service uses `kuard`_, a demo application which makes an
excellent back-end for examples.
The quickstart example uses three manifests for the sample. The first two are a
sample deployment and an associated service:
- deployment manifest: `deployment.yaml`_
.. literalinclude:: example/deployment.yaml
:language: yaml
- service manifest: `service.yaml`_
.. literalinclude:: example/service.yaml
:language: yaml
.. _`deployment.yaml`: https://raw.githubusercontent.com/jetstack/cert-manager/master/docs/tutorials/quick-start/example/deployment.yaml
.. _`service.yaml`: https://raw.githubusercontent.com/jetstack/cert-manager/master/docs/tutorials/quick-start/example/service.yaml
.. _`kuard`: https://github.com/kubernetes-up-and-running/kuard
You can create download and reference these files locally, or you can
reference them from the GitHub source repository for this documentation.
To install the example service from the tutorial files straight from GitHub,
you may use the commands:
.. code-block:: shell
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/master/docs/tutorials/quick-start/example/deployment.yaml
deployment.extensions "kuard" created
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/master/docs/tutorials/quick-start/example/service.yaml
service "kuard" created
An `ingress resource`_ is what Kubernetes uses to expose this example service
outside the cluster. You will need to download and modify the example manifest
to reflect the domain that you own or control to complete this example.
A sample ingress you can start with is:
- ingress manifest: `ingress.yaml`_
.. literalinclude:: example/ingress.yaml
:language: yaml
.. _`ingress.yaml`: https://raw.githubusercontent.com/jetstack/cert-manager/master/docs/tutorials/quick-start/example/ingress.yaml
.. _`ingress resource`: https://kubernetes.io/docs/concepts/services-networking/ingress/
You can download the sample manifest from github, edit it, and submit the manifest to Kubernetes with the command:
.. code-block:: shell
$ kubectl create --edit -f https://raw.githubusercontent.com/jetstack/cert-manager/master/docs/tutorials/quick-start/example/ingress.yaml
# edit the file in your editor, and once it is saved:
ingress.extensions "kuard" created
.. note::
The ingress example we show above has a `host` definition within it. The
nginx-ingress-controller will route traffic when the hostname requested matches the
definition in the ingress. You *can* deploy an ingress without a `host` definition
in the rule, but that pattern isn't usable with a TLS certificate, which expects a
fully qualified domain name.
Once it is deployed, you can use the command `kubectl get ingress` to see the status
of the ingress:
.. code-block:: shell
NAME HOSTS ADDRESS PORTS AGE
kuard * 80, 443 17s
It may take a few minutes, depending on your service provider, for the ingress
to be fully created. When it has been created and linked into place, the
ingress will show an address as well:
.. code-block:: shell
NAME HOSTS ADDRESS PORTS AGE
kuard * 35.199.170.62 80 9m
.. note::
The IP address on the ingress *may not* match the IP address that the
nginx-ingress-controller. This is fine, and is a quirk/implementation detail
of the service provider hosting your Kubernetes cluster. Since we are using
the nginx-ingress-controller instead of any cloud-provider specific ingress
backend, use the IP address that was defined and allocated for the
nginx-ingress-service LoadBalancer resource as the primary access point for
your service.
Make sure the service is reachable at the domain name you added above, for
example `http://example.your-domain.com`. The simplest way is to open a browser
and enter the name that you set up in DNS, and for which we just added the
ingress.
You may also use a command line tool like `curl` to check the ingress.
.. code-block:: shell
$ curl -kivL -H 'Host: example.your-domain.com' 'http://35.199.164.14'
The options on this curl command will provide verbose output, following any
redirects, show the TLS headers in the output, and not error on insecure
certificates. With nginx-ingress-controller, the service will be available
with a TLS certificate, but it will be using a self-signed certificate
provided as a default from the nginx-ingress-controller. Browsers will show
a warning that this is an invalid certificate. This is expected and normal,
as we have not yet used cert-manager to get a fully trusted certificate
for our site.
.. warning::
It is critical to make sure that your ingress is available and responding correctly
on the internet. This quickstart example uses Let's Encypt to provide the certificates,
which expects and validates both that the service is available and that during the
process of issuing a certificate uses that valdiation as proof that the request for
the domain belongs to someone with sufficient control over the domain.
Step 5 - Deploy Cert Manager
============================
We need to install cert-manager to do the work with kubernetes to request a
certificate and respond to the challenge to validate it. We can use helm to
install cert-manager. This example installed cert-manager into the
`kube-system` namespace from the public helm charts.
.. code-block:: shell
$ helm install --name cert-manager --namespace cert-manager stable/cert-manager
NAME: cert-manager
LAST DEPLOYED: Sat Nov 17 09:09:02 2018
NAMESPACE: cert-manager
STATUS: DEPLOYED
RESOURCES:
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
cert-manager-6f9ffcc9cc-rfwn5 0/1 ContainerCreating 0 0s
==> v1/ServiceAccount
NAME AGE
cert-manager 0s
==> v1beta1/ClusterRole
cert-manager 0s
==> v1beta1/ClusterRoleBinding
cert-manager 0s
==> v1beta1/Deployment
cert-manager 0s
NOTES:
cert-manager has been deployed successfully!
In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).
More information on the different types of issuers and how to configure them
can be found in our documentation:
https://cert-manager.readthedocs.io/en/latest/reference/issuers.html
For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:
https://cert-manager.readthedocs.io/en/latest/reference/ingress-shim.html
Cert-manager uses two different custom resources, also known as `CRD`_'s,
to configure and control how it operates, as well as share status of its
operation. These two resources
are:
:doc:`Issuers </reference/issuers>` (or :doc:`ClusterIssuers </reference/clusterissuers>`)
An Issuer is the definition for where cert-manager will get request TLS
certificates. An Issuer is specific to a single namespace in Kubernetes,
and a ClusterIssuer is meant to be a cluster-wide definition for the same
purpose.
:doc:`Certificate </reference/certificates>`
A certificate is the resource that cert-manager uses to expose the state
of a request as well as track upcoming expirations.
.. _`CRD`: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
Step 6 - Configure Let's Encrypt Issuer
=======================================
We will set up two issuers for Let's Encrypt in this example. The Let's Encrypt
production issuer has `very strict rate limits`_. When you are experimenting
and learning, it is very easy to hit those limits, and confuse rate limiting
with errors in configuration or operation.
.. _`very strict rate limits`: https://letsencrypt.org/docs/rate-limits/
Because of this, we will start with the Let's Encrypt staging issuer, and once
that is working switch to a production issuer.
Create this definition locally and update the email address to your own. This
email required by Let's Encryppt and used to notify you of certificate
expirations and updates.
.. literalinclude:: example/staging-issuer.yaml
:language: yaml
Once edited, apply the custom resource:
.. code-block:: shell
$ kubectl apply -f staging-issuer.yaml
issuer.certmanager.k8s.io "letsencrypt-staging" created
Also create a production issuer and deploy it. As with the staging issuer, you
will need to update this example and add in your own email address.
.. literalinclude:: example/production-issuer.yaml
:language: yaml
:emphasize-lines: 10
.. code-block:: shell
$ kubectl apply -f production-issuer.yaml
issuer.certmanager.k8s.io "letsencrypt-prod" created
Both of these issuers are configured to use the
:doc:`HTTP01 </reference/issuers/acme/http01>` challenge provider.
Check on the status of the issuer after you create it:
.. code-block::shell
:emphasize-lines: 28-32
$ kubectl describe issuer letsencrypt-staging
Name: letsencrypt-staging
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"certmanager.k8s.io/v1alpha1","kind":"Issuer","metadata":{"annotations":{},"name":"letsencrypt-staging","namespace":"default"},"spec":{"a...
API Version: certmanager.k8s.io/v1alpha1
Kind: Issuer
Metadata:
Cluster Name:
Creation Timestamp: 2018-11-17T18:03:54Z
Generation: 0
Resource Version: 9092
Self Link: /apis/certmanager.k8s.io/v1alpha1/namespaces/default/issuers/letsencrypt-staging
UID: 25b7ae77-ea93-11e8-82f8-42010a8a00b5
Spec:
Acme:
Email: your.email@your-domain.com
Http 01:
Private Key Secret Ref:
Key:
Name: letsencrypt-staging
Server: https://acme-staging-v02.api.letsencrypt.org/directory
Status:
Acme:
Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/7374163
Conditions:
Last Transition Time: 2018-11-17T18:04:00Z
Message: The ACME account was registered with the ACME server
Reason: ACMEAccountRegistered
Status: True
Type: Ready
Events: <none>
You should see the issuer listed with a registered account.
Step 7 - Deploy a TLS Ingress Resource
======================================
With all the pre-requisite configuration in place, we can now do the pieces
to request the TLS certificate. There are two primary ways to do this: using
annotations on the ingress with :doc:`ingress-shim </reference/ingress-shim>`
or directly creating a certificate resource.
In this example, we will add annotations to the ingress, and take advantage
of ingress-shim to have it create the certificate resource on our behalf.
After creating a certificate, the cert-manager will update or create a ingress
resource and use that to validate the domain. Once verified and issued,
cert-manager will create or update the secret defined in the certificate.
.. note::
The secret that is used in the ingress should match the secret defined in the certificate.
There isn't any explicit checking, so a typo will resut in the nginx-ingress-controller
falling back to its self-signed certificate. In our example, we are using annotations on
the ingress (and ingress-shim) which will create the correct secrets on your behalf.
Edit the ingress add the annotations that were commented out in our earlier
example:
.. literalinclude:: example/ingress-tls.yaml
:language: yaml
:emphasize-lines: 6-8
and apply it:
.. code-block:: shell
$ kubectl apply -f ingress-tls.yaml
ingress.extensions "kuard" configured
Cert-manager will read these annotations and use them to create a certificate,
which you can request and see:
.. code-block:: shell
$ kubectl get certificate
NAME AGE
quickstart-example-tls 38s
Cert-manager reflects the state of the process for every request in the
certificate object. You can view this information using the
`kubectl describe` command:
.. code-block:: shell
:emphasize-lines: 55-59
$ kubectl describe certificate quickstart-example-tls
Name: quickstart-example-tls
Namespace: default
Labels: <none>
Annotations: <none>
API Version: certmanager.k8s.io/v1alpha1
Kind: Certificate
Metadata:
Cluster Name:
Creation Timestamp: 2018-11-17T17:58:37Z
Generation: 0
Owner References:
API Version: extensions/v1beta1
Block Owner Deletion: true
Controller: true
Kind: Ingress
Name: kuard
UID: a3e9f935-ea87-11e8-82f8-42010a8a00b5
Resource Version: 9295
Self Link: /apis/certmanager.k8s.io/v1alpha1/namespaces/default/certificates/quickstart-example-tls
UID: 68d43400-ea92-11e8-82f8-42010a8a00b5
Spec:
Acme:
Config:
Domains:
example.your-domain.com
Http 01:
Ingress:
Ingress Class: nginx
Dns Names:
example.your-domain.com
Issuer Ref:
Kind: Issuer
Name: letsencrypt-staging
Secret Name: quickstart-example-tls
Status:
Acme:
Order:
URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/7374163/13665676
Conditions:
Last Transition Time: 2018-11-17T18:05:57Z
Message: Certificate issued successfully
Reason: CertIssued
Status: True
Type: Ready
Last Transition Time: <nil>
Message: Order validated
Reason: OrderValidated
Status: False
Type: ValidateFailed
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateOrder 9m cert-manager Created new ACME order, attempting validation...
Normal DomainVerified 8m cert-manager Domain "example.your-domain.com" verified with "http-01" validation
Normal IssueCert 8m cert-manager Issuing certificate...
Normal CertObtained 7m cert-manager Obtained certificate from ACME server
Normal CertIssued 7m cert-manager Certificate issued Successfully
The events associated with this resource and listed at the bottom
of the `describe` results show the state of the request. In the above
example the certificate was validated and issued within a couple of minutes.
Once complete, cert-manager will have created a secret with the details of
the certificate based on the secret used in the ingress resource. You can
use the describe command as well to see some details:
.. code-block:: shell
$ kubectl describe secret quickstart-example-tls
Name: quickstart-example-tls
Namespace: default
Labels: certmanager.k8s.io/certificate-name=quickstart-example-tls
Annotations: certmanager.k8s.io/alt-names=example.your-domain.com
certmanager.k8s.io/common-name=example.your-domain.com
certmanager.k8s.io/issuer-kind=Issuer
certmanager.k8s.io/issuer-name=letsencrypt-staging
Type: kubernetes.io/tls
Data
====
tls.crt: 3566 bytes
tls.key: 1675 bytes
Now that we have confidence that everything is configured correctly, you
can update the annotations in the ingress to specify the production issuer:
.. literalinclude:: example/ingress-tls-final.yaml
:language: yaml
.. code-block:: shell
$ kubectl apply -f ingress.yaml
ingress.extensions "kuard" configured
You will also need to delete the existing secret, which cert-manager is watching
and will cause it to reprocess the request with the updated issuer.
.. code-block:: shell
$ kubectl delete secret quickstart-example-tls
secret "quickstart-example-tls" deleted
This will start the process to get a new certificate, and using describe
you can see the status. Once the production certificate has been updated,
you should see the example KUARD running at your domain with a signed TLS
certificate.
.. code-block:: shell
:emphasize-lines: 55-59
$ kubectl describe certificate
Name: quickstart-example-tls
Namespace: default
Labels: <none>
Annotations: <none>
API Version: certmanager.k8s.io/v1alpha1
Kind: Certificate
Metadata:
Cluster Name:
Creation Timestamp: 2018-11-17T18:36:48Z
Generation: 0
Owner References:
API Version: extensions/v1beta1
Block Owner Deletion: true
Controller: true
Kind: Ingress
Name: kuard
UID: a3e9f935-ea87-11e8-82f8-42010a8a00b5
Resource Version: 283686
Self Link: /apis/certmanager.k8s.io/v1alpha1/namespaces/default/certificates/quickstart-example-tls
UID: bdd93b32-ea97-11e8-82f8-42010a8a00b5
Spec:
Acme:
Config:
Domains:
example.your-domain.com
Http 01:
Ingress:
Ingress Class: nginx
Dns Names:
example.your-domain.com
Issuer Ref:
Kind: Issuer
Name: letsencrypt-prod
Secret Name: quickstart-example-tls
Status:
Acme:
Order:
URL: https://acme-v02.api.letsencrypt.org/acme/order/45980184/182533829
Conditions:
Last Transition Time: 2018-11-19T19:16:10Z
Message: Certificate issued successfully
Reason: CertIssued
Status: True
Type: Ready
Last Transition Time: <nil>
Message: Order validated
Reason: OrderValidated
Status: False
Type: ValidateFailed
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateOrder 26s cert-manager Created new ACME order, attempting validation...
Normal DomainVerified 9s cert-manager Domain "example.your-domain.com" verified with "http-01" validation
Normal IssueCert 8s cert-manager Issuing certificate...
Normal CertObtained 6s cert-manager Obtained certificate from ACME server
Normal CertIssued 6s cert-manager Certificate issued successfully