added istio controller for cert-manager

This commit is contained in:
ston1th 2019-08-10 21:51:09 +02:00
commit b23161a08d
10 changed files with 373 additions and 0 deletions

View file

@ -0,0 +1,3 @@
FROM flant/shell-operator:latest
ADD hooks /hooks
ADD cleanup.sh /

View file

@ -0,0 +1,13 @@
CC=docker
APP=certman-istio-controller
TAG=127.0.0.1:5000/cert/$(APP):$(VERSION)
all: build push
build:
$(CC) build --build-arg VERSION=$(VERSION) -t $(TAG) .
push:
$(CC) push $(TAG)
.PHONY: build push

View file

@ -0,0 +1,32 @@
# Istio Cert Manager
The Istio Cert Manager is an addon controller to support Cert-Manager's `ACME HTTP01` Issuer with Istio `Gateway` and `VirtualService` intgration.
## Install
Create the Custom Resource Definition:
```
kubectl apply -f crd.yaml
```
Grant permissions for the new controller:
```
kubectl apply -f rbac.yaml
```
Create the controller pod:
```
kubectl apply -f pod.yaml
```
## Cleanup
```
kubectl -n cert-manager exec certman-istio-controller /cleanup.sh
kubectl delete -f pod.yaml
kubectl delete -f rbac.yaml
kubectl delete -f crd.yaml
```

View file

@ -0,0 +1,7 @@
#!/bin/bash
source /hooks/common/functions.sh
for refmap in $(kubectl get refmap -ojson | jq -r '.items[] | .metadata.name'); do
delete "${refmap}"
done

View file

@ -0,0 +1,43 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: refmaps.cic.giftfish.de
spec:
group: cic.giftfish.de
versions:
- name: v1alpha1
served: true
storage: true
scope: Cluster
names:
plural: refmaps
singular: refmap
kind: RefMap
shortNames:
- rm
preserveUnknownFields: false
validation:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
namespace:
type: string
gateway:
type: object
properties:
ref:
type: string
action:
type: string
pattern: '^(none|delete)$'
virtualService:
type: object
properties:
ref:
type: string
action:
type: string
pattern: '^(clear|delete)$'

View file

@ -0,0 +1,188 @@
config() {
cat <<EOF
{
"onKubernetesEvent": [
{
"kind": "Ingress",
"event": ["$1"],
"selector": {
"matchLabels": {
"certmanager.k8s.io/acme-http01-solver": "true"
}
}
}
]
}
EOF
}
mkmap() {
kubectl apply -f - <<EOF
apiVersion: cic.giftfish.de/v1alpha1
kind: RefMap
metadata:
name: "$1"
spec:
namespace: "$2"
gateway:
ref: "$3"
action: "$4"
virtualService:
ref: "$5"
action: "$6"
EOF
}
getmap() { kubectl get refmap $1 -ojson; }
delmap() { kubectl delete refmap $1; }
mkgw() {
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: "$1"
namespace: "$2"
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts: ["$3"]
EOF
}
delgw() { kubectl -n $2 delete gateway $1; }
mkvs() {
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: "$1"
namespace: "$2"
spec:
gateways: ["$1"]
hosts: ["$3"]
http:
- match:
- port: 80
uri:
exact: "$4"
route:
- destination:
port:
number: $6
host: "$5.$2.svc.cluster.local"
EOF
}
addvs() {
insert=$(jq -c -M . <<EOF
{
"match": [
{
"port": 80,
"uri": {
"exact": "$3"
}
}
],
"route": [
{
"destination": {
"host": "$4.$2.svc.cluster.local",
"port": {
"number": $5
}
}
}
]
}
EOF
)
kubectl -n $2 get virtualservice $1 -ojson | jq ".spec.http |= [${insert}] + ." | kubectl -n $2 apply -f -
}
clearvs() { kubectl -n $2 get virtualservice $1 -ojson | jq -r '.spec.http |= .[1:]' | kubectl -n $2 apply -f -; }
delvs() { kubectl -n $2 delete virtualservice $1; }
mkdr() {
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: $1
namespace: $2
spec:
host: "$3.$2.svc.cluster.local"
trafficPolicy:
tls:
mode: DISABLE
EOF
}
deldr() { kubectl -n $2 delete destinationrule $1; }
delete() {
tmp=$(mktemp)
getmap $1 >${tmp} || return 0
ns=$(jq -r '.spec.namespace' ${tmp})
gwName=$(jq -r '.spec.gateway.ref' ${tmp})
gwAction=$(jq -r '.spec.gateway.action' ${tmp})
vsName=$(jq -r '.spec.virtualService.ref' ${tmp})
vsAction=$(jq -r '.spec.virtualService.action' ${tmp})
rm -f ${tmp}
if [[ "${gwName}" != "" ]]; then
case ${gwAction} in
delete) delgw "${gwName}" "${ns}" ;;
none|*) ;;
esac
fi
if [[ "${vsName}" != "" ]]; then
case ${vsAction} in
delete) delvs "${vsName}" "${ns}" ;;
clear) clearvs "${vsName}" "${ns}" ;;
esac
fi
deldr "$1" "${ns}"
delmap "$1"
}
add() {
res=$1
ns=$2
tmp=$(mktemp)
kubectl -n ${ns} get ingress ${res} -ojson >${tmp} || return 0
host=$(jq -r '.spec.rules[0].host' ${tmp})
svcName=$(jq -r '.spec.rules[0].http.paths[0].backend.serviceName' ${tmp})
svcPort=$(jq -r '.spec.rules[0].http.paths[0].backend.servicePort' ${tmp})
path=$(jq -r '.spec.rules[0].http.paths[0].path' ${tmp})
rm -f ${tmp}
gwName=
for gw in $(kubectl -n ${ns} get gateway -ojson | jq -r '.items[] | .metadata.name'); do
contains=$(kubectl -n ${ns} get gateway ${gw} -ojson | jq -r ".spec.servers[0].hosts | contains([\"${host}\"])")
[[ "${contains}" == "true" ]] && { gwName=${gw}; break; }
done
if [[ "${gwName}" == "" ]]; then
gwName=${res}
mkgw "${gwName}" "${ns}" "${host}"
gwAction=delete
else
gwAction=none
fi
vsName=
vsAction=
for vs in $(kubectl -n ${ns} get virtualservice -ojson | jq -r '.items[] | .metadata.name'); do
contains=$(kubectl -n ${ns} get virtualservice ${vs} -ojson | jq -r ".spec.hosts | contains([\"${host}\"])")
[[ "${contains}" == "true" ]] && { vsName=${vs}; break; }
done
if [[ "${vsName}" == "" ]]; then
vsName=${res}
mkvs "${vsName}" "${ns}" "${host}" "${path}" "${svcName}" "${svcPort}"
vsAction=delete
else
addvs "${vsName}" "${ns}" "${path}" "${svcName}" "${svcPort}"
vsAction=clear
fi
mkdr "${res}" "${ns}" "${svcName}"
mkmap "${res}" "${ns}" "${gwName}" "${gwAction}" "${vsName}" "${vsAction}"
}

View file

@ -0,0 +1,12 @@
#!/bin/bash
source /hooks/common/functions.sh
if [[ $1 == "--config" ]]; then
config add
else
json=${BINDING_CONTEXT_PATH}
ns=$(jq -r '.[0].resourceNamespace' ${json})
res=$(jq -r '.[0].resourceName' ${json})
add "${res}" "${ns}"
fi

View file

@ -0,0 +1,9 @@
#!/bin/bash
source /hooks/common/functions.sh
if [[ $1 == "--config" ]]; then
config delete
else
delete "$(jq -r '.[0].resourceName' ${BINDING_CONTEXT_PATH})"
fi

View file

@ -0,0 +1,21 @@
apiVersion: v1
kind: Pod
metadata:
name: certman-istio-controller
namespace: cert-manager
labels:
app: certman-istio-controller
version: v1
spec:
containers:
- name: certman-istio-controller
image: 127.0.0.1:5000/cert/certman-istio-controller:v1
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
imagePullPolicy: Always
serviceAccountName: certman-istio-controller

View file

@ -0,0 +1,45 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: certman-istio-controller
namespace: cert-manager
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: certman-istio-controller
rules:
- apiGroups:
- extensions
resources:
- ingresses
verbs: ["get", "list", "watch"]
- apiGroups:
- networking.istio.io
resources:
- gateways
- virtualservices
verbs: ["*"]
- apiGroups:
- networking.istio.io
resources:
- destinationrules
verbs: ["get", "create", "delete"]
- apiGroups:
- cic.giftfish.de
resources:
- refmaps
verbs: ["get", "list", "create", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: certman-istio-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: certman-istio-controller
subjects:
- kind: ServiceAccount
name: certman-istio-controller
namespace: cert-manager