# Prerequisites

Many of the examples in this directory have common prerequisites.

## Deploying a controller

Unless you're running on a cloudprovider that supports Ingress out of the box
(eg: GCE/GKE), you will need to deploy a controller. You can do so following
[these instructions](/examples/deployment).

## Firewall rules

If you're using a generic controller (eg the nginx ingress controller), you
will need to create a firewall rule that targets port 80/443 on the specific VMs
the nginx controller is running on. On cloudproviders, the respective backend
will auto-create firewall rules for your Ingress.

If you'd like to auto-create firewall rules for an Ingress controller,
you can put it behind a Service of `Type=Loadbalancer` as shown in
[this example](/examples/static-ip/nginx#acquiring-an-ip).

## TLS certificates

Unless otherwise mentioned, the TLS secret used in examples is a 2048 bit RSA
key/cert pair with an arbitrarily chosen hostname, created as follows

```console
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
Generating a 2048 bit RSA private key
................+++
................+++
writing new private key to 'tls.key'
-----

$ kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret "tls-secret" created
```

## CA Authentication
You can act as your very own CA, or use an existing one. As an exercise / learning, we're going to generate our
own CA, and also generate a client certificate.

These instructions are based in CoreOS OpenSSL [instructions](https://coreos.com/kubernetes/docs/latest/openssl.html)

### Generating a CA

First of all, you've to generate a CA. This is going to be the one who will sign your client certificates.
In real production world, you may face CAs with intermediate certificates, as the following:

```console
$ openssl s_client -connect www.google.com:443
[...]
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority

```

To generate our CA Certificate, we've to run the following commands:

```console
$ openssl genrsa -out ca.key 2048
$ openssl req -x509 -new -nodes -key ca.key -days 10000 -out ca.crt -subj "/CN=example-ca"
```

This will generate two files: A private key (ca.key) and a public key (ca.crt). This CA is valid for 10000 days.
The ca.crt can be used later in the step of creation of CA authentication secret.

### Generating the client certificate
The following steps generates a client certificate signed by the CA generated above. This client can be
used to authenticate in a tls-auth configured ingress.

First, we need to generate an 'openssl.cnf' file that will be used while signing the keys:

```
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
```

Then, a user generates his very own private key (that he needs to keep secret)
and a CSR (Certificate Signing Request) that will be sent to the CA to sign and generate a certificate.

```console
$ openssl genrsa -out client1.key 2048
$ openssl req -new -key client1.key -out client1.csr -subj "/CN=client1" -config openssl.cnf
```

As the CA receives the generated 'client1.csr' file, it signs it and generates a client.crt certificate:

```console
$ openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt -days 365 -extensions v3_req -extfile openssl.cnf
```

Then, you'll have 3 files: the client.key (user's private key), client.crt (user's public key) and client.csr (disposable CSR).


### Creating the CA Authentication secret
If you're using the CA Authentication feature, you need to generate a secret containing 
all the authorized CAs. You must download them from your CA site in PEM format (like the following):

```
-----BEGIN CERTIFICATE-----
[....]
-----END CERTIFICATE-----
``` 

You can have as many certificates as you want. If they're in the binary DER format, 
you can convert them as the following:

```console
$ openssl x509 -in certificate.der -inform der -out certificate.crt -outform pem
```

Then, you've to concatenate them all in only one file, named 'ca.crt' as the following:


```console
$ cat certificate1.crt certificate2.crt certificate3.crt >> ca.crt
```

The final step is to create a secret with the content of this file. This secret is going to be used in 
the TLS Auth directive:

```console
$ kubectl create secret generic caingress --namespace=default --from-file=ca.crt
```

## Test HTTP Service

All examples that require a test HTTP Service use the standard http-svc pod,
which you can deploy as follows

```console
$ kubectl create -f http-svc.yaml
service "http-svc" created
replicationcontroller "http-svc" created

$ kubectl get po
NAME             READY     STATUS    RESTARTS   AGE
http-svc-p1t3t   1/1       Running   0          1d

$ kubectl get svc
NAME             CLUSTER-IP     EXTERNAL-IP   PORT(S)            AGE
http-svc         10.0.122.116   <pending>     80:30301/TCP       1d
```

You can test that the HTTP Service works by exposing it temporarily
```console
$ kubectl patch svc http-svc -p '{"spec":{"type": "LoadBalancer"}}'
"http-svc" patched

$ kubectl get svc http-svc
NAME             CLUSTER-IP     EXTERNAL-IP   PORT(S)            AGE
http-svc         10.0.122.116   <pending>     80:30301/TCP       1d

$ kubectl describe svc http-svc
Name:				    http-svc
Namespace:			    default
Labels:			        app=http-svc
Selector:		        app=http-svc
Type:			        LoadBalancer
IP:			            10.0.122.116
LoadBalancer Ingress:	108.59.87.136
Port:			        http	80/TCP
NodePort:		        http	30301/TCP
Endpoints:		        10.180.1.6:8080
Session Affinity:	    None
Events:
  FirstSeen	LastSeen	Count	From			SubObjectPath	Type		Reason			Message
  ---------	--------	-----	----			-------------	--------	------			-------
  1m		1m		1	{service-controller }			Normal		Type			ClusterIP -> LoadBalancer
  1m		1m		1	{service-controller }			Normal		CreatingLoadBalancer	Creating load balancer
  16s		16s		1	{service-controller }			Normal		CreatedLoadBalancer	Created load balancer

$ curl 108.59.87.126
CLIENT VALUES:
client_address=10.240.0.3
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://108.59.87.136:8080/

SERVER VALUES:
server_version=nginx: 1.9.11 - lua: 10001

HEADERS RECEIVED:
accept=*/*
host=108.59.87.136
user-agent=curl/7.46.0
BODY:
-no body in request-

$ kubectl patch svc http-svc -p '{"spec":{"type": "NodePort"}}'
"http-svc" patched
```

## Ingress Class

If you have multiple Ingress controllers in a single cluster, you can pick one
by specifying the `ingress.class` annotation, eg creating an Ingress with an
annotation like

```yaml
metadata:
  name: foo
  annotations:
    kubernetes.io/ingress.class: "gce"
```

will target the GCE controller, forcing the nginx controller to ignore it, while
an annotation like

```yaml
metadata:
  name: foo
  annotations:
    kubernetes.io/ingress.class: "nginx"
```

will target the nginx controller, forcing the GCE controller to ignore it.

__Note__: Deploying multiple ingress controller and not specifying the
annotation will result in both controllers fighting to satisfy the Ingress.
