├── test ├── README.md ├── cert_image │ ├── Dockerfile │ ├── create_cert.sh │ ├── in.req │ └── domain.key ├── system.bats └── install_cert.bats ├── k8s ├── reg_service.yaml ├── copy-certs.yaml ├── copy-certs-templ.yaml ├── create-certs.yaml └── reg_controller.yaml ├── images ├── create_certs │ ├── in.req │ ├── Dockerfile │ └── create_certs.sh └── copy_certs │ ├── Dockerfile │ └── copy_certs.sh ├── README.md ├── LICENSE └── reg-tool.sh /test/README.md: -------------------------------------------------------------------------------- 1 | # Tests 2 | 3 | Currently the only test is a happy-path system test. 4 | 5 | You probably don't want to run this, as it will restart any minikube server, 6 | edit /etc/hosts and add a test certificate. 7 | -------------------------------------------------------------------------------- /test/cert_image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie 2 | 3 | RUN apt-get update && export TERM=xterm && \ 4 | apt-get install -y openssl \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | COPY create_cert.sh / 8 | COPY in.req / 9 | RUN chmod +x /create_cert.sh 10 | 11 | ENTRYPOINT /create_cert.sh 12 | -------------------------------------------------------------------------------- /test/cert_image/create_cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | if [[ ! -d /certs ]]; then 6 | mkdir /certs 7 | fi 8 | 9 | openssl req -config /in.req -newkey rsa:4096 -nodes -sha256 \ 10 | -keyout /certs/domain.key -x509 -days 265 -out /certs/ca.crt 11 | 12 | #should now have /certs/domain.key and /certs/ca.crt 13 | -------------------------------------------------------------------------------- /k8s/reg_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: kube-registry 5 | namespace: kube-system 6 | labels: 7 | k8s-app: kube-registry 8 | kubernetes.io/name: "KubeRegistry" 9 | spec: 10 | selector: 11 | k8s-app: kube-registry 12 | ports: 13 | - name: registry 14 | port: 5000 15 | nodePort: 31000 16 | protocol: TCP 17 | type: NodePort 18 | -------------------------------------------------------------------------------- /test/cert_image/in.req: -------------------------------------------------------------------------------- 1 | [ req ] 2 | distinguished_name = req_distinguished_name 3 | prompt = no 4 | 5 | [ req_distinguished_name ] 6 | C = GB 7 | ST = Test State or Province 8 | L = Test Locality 9 | O = Local Secure Registry for Kubernetes 10 | CN = test-docker-reg 11 | emailAddress = test@email.address 12 | 13 | -------------------------------------------------------------------------------- /images/create_certs/in.req: -------------------------------------------------------------------------------- 1 | [ req ] 2 | distinguished_name = req_distinguished_name 3 | prompt = no 4 | 5 | [ req_distinguished_name ] 6 | C = GB 7 | ST = Test State or Province 8 | L = Test Locality 9 | O = Local Secure Registry for Kubernetes 10 | CN = kube-registry.kube-system.svc.cluster.local 11 | emailAddress = test@email.address 12 | 13 | -------------------------------------------------------------------------------- /images/copy_certs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | ed curl \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | # This should download the latest stable version of kubectl 8 | # It's not great from a provenance pov, but it's basically the same as the 9 | # official instructions 10 | RUN curl -o /usr/local/bin/kubectl -sSL https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl 11 | RUN chmod +x /usr/local/bin/kubectl 12 | COPY copy_certs.sh / 13 | RUN chmod +x /copy_certs.sh 14 | ENTRYPOINT /copy_certs.sh 15 | -------------------------------------------------------------------------------- /images/create_certs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie 2 | 3 | RUN apt-get update && export TERM=xterm && \ 4 | apt-get install -y openssl curl \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | # This should download the latest stable version of kubectl 8 | # It's not great from a provenance pov, but it's basically the same as the 9 | # official instructions 10 | RUN curl -o /usr/local/bin/kubectl -sSL https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl 11 | RUN chmod +x /usr/local/bin/kubectl 12 | 13 | COPY create_certs.sh / 14 | COPY in.req / 15 | RUN chmod +x /create_certs.sh 16 | 17 | ENTRYPOINT /create_certs.sh 18 | -------------------------------------------------------------------------------- /k8s/copy-certs.yaml: -------------------------------------------------------------------------------- 1 | kind: Job 2 | apiVersion: batch/v1 3 | metadata: 4 | name: copy-certs 5 | spec: 6 | template: 7 | metadata: 8 | name: copy-certs 9 | spec: 10 | restartPolicy: OnFailure 11 | serviceAccountName: registry-secret-manager 12 | containers: 13 | - name: copy-certs 14 | image: amouat/copy-certs-auto 15 | imagePullPolicy: Always 16 | volumeMounts: 17 | - mountPath: /etc/docker 18 | name: cert-dir 19 | - mountPath: /hostfile 20 | name: host-dir 21 | volumes: 22 | - name: cert-dir 23 | hostPath: 24 | path: /etc/docker 25 | - name: host-dir 26 | hostPath: 27 | path: /etc/hosts 28 | -------------------------------------------------------------------------------- /images/create_certs/create_certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | mkdir certs 6 | 7 | #get rid of any old certs; careful here, maybe require flag? 8 | kubectl delete secret registry-cert || true 9 | kubectl delete secret --namespace=kube-system registry-cert || true 10 | kubectl delete secret --namespace=kube-system registry-key || true 11 | 12 | openssl req -config /in.req -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key -x509 -days 265 -out certs/ca.crt 13 | #put the public key in both the default and kube-system namespaces 14 | kubectl create secret generic registry-cert --from-file=./certs/ca.crt 15 | kubectl create --namespace=kube-system secret generic registry-cert --from-file=./certs/ca.crt 16 | kubectl create --namespace=kube-system secret generic registry-key --from-file=./certs/domain.key 17 | -------------------------------------------------------------------------------- /k8s/copy-certs-templ.yaml: -------------------------------------------------------------------------------- 1 | {{range .items}}{{if not .spec.unschedulable}} 2 | kind: Job 3 | apiVersion: batch/v1 4 | metadata: 5 | name: copy-certs-{{.metadata.uid}} 6 | spec: 7 | template: 8 | metadata: 9 | name: copy-certs-{{.metadata.uid}} 10 | spec: 11 | restartPolicy: OnFailure 12 | serviceAccountName: registry-secret-manager 13 | containers: 14 | - name: copy-certs-{{.metadata.uid}} 15 | image: amouat/copy-certs-auto 16 | imagePullPolicy: Always 17 | volumeMounts: 18 | - mountPath: /etc/docker 19 | name: cert-dir 20 | - mountPath: /hostfile 21 | name: host-dir 22 | securityContext: 23 | privileged: true 24 | volumes: 25 | - name: cert-dir 26 | hostPath: 27 | path: /etc/docker 28 | - name: host-dir 29 | hostPath: 30 | path: /etc/hosts 31 | nodeSelector: 32 | kubernetes.io/hostname: "{{.metadata.name}}" 33 | --- 34 | {{end}}{{end}} 35 | -------------------------------------------------------------------------------- /k8s/create-certs.yaml: -------------------------------------------------------------------------------- 1 | kind: ServiceAccount 2 | apiVersion: v1 3 | metadata: 4 | name: registry-secret-manager 5 | 6 | --- 7 | kind: ClusterRole 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | metadata: 10 | name: secret-manager-role 11 | rules: 12 | - apiGroups: [""] 13 | resources: ["secrets"] 14 | verbs: ["create","delete","get","list","watch"] 15 | 16 | --- 17 | kind: ClusterRoleBinding 18 | apiVersion: rbac.authorization.k8s.io/v1 19 | metadata: 20 | name: secret-manager 21 | roleRef: 22 | kind: ClusterRole 23 | name: secret-manager-role 24 | apiGroup: rbac.authorization.k8s.io 25 | subjects: 26 | - kind: ServiceAccount 27 | name: registry-secret-manager 28 | namespace: default 29 | 30 | --- 31 | kind: Job 32 | apiVersion: batch/v1 33 | metadata: 34 | name: create-certs 35 | spec: 36 | template: 37 | metadata: 38 | name: create-certs 39 | spec: 40 | restartPolicy: OnFailure 41 | serviceAccountName: registry-secret-manager 42 | containers: 43 | - name: create-certs 44 | image: amouat/create-certs-auto 45 | imagePullPolicy: Always 46 | -------------------------------------------------------------------------------- /images/copy_certs/copy_certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | registry_host="kube-registry.kube-system.svc.cluster.local" 6 | registry_port="31000" 7 | registry_host_port="${registry_host}:${registry_port}" 8 | 9 | 10 | mkdir --parents "/etc/docker/certs.d/$registry_host_port/" 11 | echo "copying certs" 12 | kubectl get secret registry-cert \ 13 | -o go-template --template '{{(index .data "ca.crt")}}' \ 14 | | base64 -d \ 15 | > "/etc/docker/certs.d/$registry_host_port/ca.crt" 16 | echo "Sucessfully copied certs" 17 | 18 | echo "Adding entry to /etc/hosts" 19 | # sed would be a better choice than ed, but it wants to create a temp file :( 20 | printf "g/$registry_host/d\nw\n" | ed /hostfile 21 | #ideally we don't want to use a 127 address as the insecure registry logic gets triggered 22 | schedulable_nodes=$(kubectl get nodes -o template \ 23 | --template='{{range.items}}{{if not .spec.unschedulable}}{{range.status.addresses}}{{if eq .type "InternalIP"}}{{.address}} {{end}}{{end}}{{end}}{{end}}') 24 | 25 | #choosing a host at random isn't ideal, but I don't how to find the host for the pod 26 | local_ip=$(shuf -e -n1 $schedulable_nodes) 27 | echo "$local_ip $registry_host #Added by secure-kube-registry script" >> /hostfile 28 | echo "Added entry" 29 | 30 | -------------------------------------------------------------------------------- /test/system.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | function setup { 4 | minikube start --vm-driver=kvm > /dev/null || true 5 | run kubectl cluster-info > /dev/null 6 | while [[ "$status" != 0 ]] 7 | do 8 | sleep 1 9 | run kubectl cluster-info > /dev/null 10 | done 11 | } 12 | 13 | @test "happy path" { 14 | ../reg-tool.sh install-k8s-reg -y > /dev/null 15 | sudo ../reg-tool.sh install-cert --add-host $(minikube ip) > /dev/null 16 | # need a restart on Docker for Mac 17 | if [[ "$(uname -s)" = "Darwin" ]]; then 18 | killall com.docker.osx.hyperkit.linux 19 | sleep 1 20 | run docker pull alpine:latest > /dev/null 21 | while [[ "$status" != 0 ]] 22 | do 23 | sleep 1 24 | run docker pull alpine:latest &> /dev/null 25 | done 26 | fi 27 | docker pull alpine:latest 28 | docker tag alpine:latest kube-registry.kube-system.svc.cluster.local:31000/alpine:latest 29 | # this typically fails, presumably due to caching of DNS in lib used by Docker 30 | # Give DNS 5 secs 31 | sleep 5 32 | docker push kube-registry.kube-system.svc.cluster.local:31000/alpine:latest > /dev/null 33 | kubectl delete deployment test-deploy > /dev/null || true 34 | kubectl run test-deploy --image kube-registry.kube-system.svc.cluster.local:31000/alpine:latest --command sleep 100 > /dev/null 35 | #need to check don't get pull error here 36 | kubectl delete deployment test-deploy 37 | } 38 | 39 | -------------------------------------------------------------------------------- /k8s/reg_controller.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ReplicationController 3 | metadata: 4 | name: kube-registry 5 | namespace: kube-system 6 | labels: 7 | k8s-app: kube-registry 8 | version: v0 9 | # A minikube issue prevents the following from working 10 | # kubernetes.io/cluster-service: "true" 11 | spec: 12 | replicas: 1 13 | selector: 14 | k8s-app: kube-registry 15 | version: v0 16 | template: 17 | metadata: 18 | labels: 19 | k8s-app: kube-registry 20 | version: v0 21 | # A minikube issue prevents the following from working 22 | # kubernetes.io/cluster-service: "true" 23 | spec: 24 | containers: 25 | - name: registry 26 | image: registry:2 27 | resources: 28 | limits: 29 | cpu: 100m 30 | memory: 100Mi 31 | env: 32 | - name: REGISTRY_HTTP_ADDR 33 | value: :5000 34 | - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY 35 | value: /var/lib/registry 36 | - name: REGISTRY_HTTP_TLS_CERTIFICATE 37 | value: /cert/ca.crt 38 | - name: REGISTRY_HTTP_TLS_KEY 39 | value: /key/domain.key 40 | - name: REGISTRY_LOG_LEVEL 41 | value: debug 42 | volumeMounts: 43 | - name: image-store 44 | mountPath: /var/lib/registry 45 | - name: registry-cert 46 | mountPath: /cert/ 47 | readOnly: true 48 | - name: registry-key 49 | mountPath: /key/ 50 | readOnly: true 51 | ports: 52 | - containerPort: 5000 53 | name: registry 54 | protocol: TCP 55 | volumes: 56 | - name: image-store 57 | - name: registry-cert 58 | secret: 59 | secretName: registry-cert 60 | - name: registry-key 61 | secret: 62 | secretName: registry-key 63 | -------------------------------------------------------------------------------- /test/cert_image/domain.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC1MjFhiRCK4kL5 3 | yQAsXYab+0Q8l4VMe2Swd0LbOWY4egdeM9bX7OlrMuqJqSqGo+yozv+XOjwYD1Ss 4 | 5vJUgQ4cL+2ujm2pl0X6tIamYpviqWLDeXRn5j3Zr3w9/JBOvae2VBARKXsFzywm 5 | yY5mG/Z1ii2GnIPoxkTiBLzWmMNDndVRuUsGMWkGTHIDSjKLQeYcfh+k2YEkdvYW 6 | aq6KqbgljyxhBtpqE65yI6ch/Q6n9qgpy7kySuN/Mm8gLy7Du/l9yL4uDobqP9jQ 7 | 1SRzBXZpv7GxUsVMUuyfNx10DhaAfDE0Gw+cA4SLCP2fBFsAFo7CdVfs/lIlDUPh 8 | +MDPCNh7CGNzGgxHeQTc/p21Au9Fy4y0uGmePHQPQtHIEqdrMa5GRA4QRm/GEyFN 9 | K5auL7xm933DvNpiSh5+GN0Zo9Vg/KmuVV8/GWQOys94YdsY7/+ZcYu7FJHd+Ach 10 | hXQyv7mvqsgK2CedpFqECPQiNMipR5Cv23h9PKklXy4Ld/kzcWxoCQ4qisClXN9U 11 | Ku8CsXlNhaiD5oNa1FMbJy1Rbo50CA6xlGcvlBQwpJwrYMnLZWtT2KrPAO6ndmnL 12 | plrX/BTxZpCvYTDXNu0MoqTOdJqD5FdAXSuexeBa6yKiKx0AGtEIWGd7yyLUGYly 13 | luZaKuGrOW8bhVymdjDq3eHhqQSuAQIDAQABAoICAFKUKYU2Hl/tdnC4dmfByBNW 14 | lGa493s/0UfLUqDuq/OZSbpZDdUil87PSayreEIce0MD8+BMHg8pDYIvTsnMd03J 15 | Wh1vs/LSioYTuDokPr8yS1yjAbZIbG/FVm45qNr5/HFQJnJr4TFolcqnmUpX/B7d 16 | dpoews9XbRVE63sx6+vpBstUEykjY6YHOP7e1eI5ilH5+Rn8NqsTvFvDCwEPEGmt 17 | sqAVq30ksyA5t3X6Cq/p7gH+YszU7JGPvq2AU2PJS49T6bi7zij8KCgku5PgLXNM 18 | dgNGobyDHmwBhl7Z/M9ZymLg4mBMCiADXPMX3RFRNobRS90qmu1f+kwGPnkcouvL 19 | N8ZOZ00GcaI1MMv6CGsgsoW17wrFCej/WrAiWvJDQHOO0d6btodzi5leAPfvfJgZ 20 | +xN1sx0AN5vLDgityIC9ix66yh9xzO+DQVeq6a8+9fJdirCbuVxllR4BuldQcufa 21 | FfVrVIthDLl6Kapw7e0MIwF2lJRA8pt3+foIUmi/iZs4CWWcdddG4PTAglZPDbF3 22 | kjep5TS02GFDPali8Bu/PId4tRpV0liEMI09n/EmTpVem9iCw/AEG63Zvr9qMhLZ 23 | cr7sKsLG5QGInxFp3Xh8nMat2YqWEivPO3dkPkTkeH9cWr1goCxG67zEwQzb8Pyg 24 | H2gbrN96tQFtOznd0N0BAoIBAQDZq96kuk0R4TZSpL9r8MQLP7ZlV8QieC+XUYhh 25 | /VIFdwKjmDuMNEwujH10cex6dushBWF/xKt3lpYSQMoxqS8ySTlvp+1ecymxTkag 26 | QqzBL4s2Sq2IcRIQX7fyBKeh0HjSpUZLmRxWVRdOw1Es3Xm3fbi0MC/zKs+HnGb6 27 | Tm5Yz4RC61l74FUZJRzyazH4StkSEutL8EJeDrsg7ltwDpW/EJNJQzkdAtrczrcP 28 | DxpPFBDRIdKnePPyDS9klXLIDkk3NeVPjuOtA4oCU3Y6SVZmemBaohkOUK1fHwLt 29 | B64GqNmk7ZAUwLnbCPb2yrVTIoM9ftaBtl3YyPGzshQw83XJAoIBAQDVGhl/HJpB 30 | TQ+Ooj6gCrO6Wv67Y9qL54aWujpMbOVQ8fxsv1u5mv/BPhCIdnk6OI/n/xu1myAD 31 | EnLam7rTW7DUhq5gIzoKX8sB+nd88mZq5xVMYxzrl7owZFsm9SPUNxr2djg/Q2ZG 32 | cYkOOoOGxFvxcNJjIAcpsAJw11M3uTqJfZCNWypryoLT2yp9IBe/ju0WMmskWvM2 33 | NwU+PcFubK4wpgTg2sYzwxQawtkqJ7nYQSa8GXeCmNGVeODHXxTVQHN+iZWFQj0q 34 | vbnGihoQBR1/U4EfgWSrn7TwtodZUzGfVr3mGJK3VHMd1DUiB4oge18ahQ+bfFyA 35 | 1+AvzcHwyvJ5AoIBADsG7H1nN/cdR4npuy8eP0t9n4yj3EAsr1stdPp9o3xv5XtP 36 | kPZYSEBnQK4PJr2e+ewedW4cexMW9uNERpBo/K96Q+UPeMMgH7JBM83JxucsaWfz 37 | oFNbtjZSfqNWt86dpeYZg5KElraipItrU9wCwzsLEMdsOdSLS3PO6e3+ztWukINF 38 | JyL8lpcXBV6Hyyk1wt+v2bbiFF1FSWGIwasFiX4ilI5NeHNxjsBKHkIrKks/eb/8 39 | mA9qMVz2Tl/MVzABD8G1D9YfPYZxaz9uOqVbtd5cWTy6sGi9YAZndneomXyc1Uhw 40 | U54NFVlcePw7xCgjN8u5VZofRhu/givkoq0TmGECggEBALxY6RgT67KzrYBfngJN 41 | 8zROoL53Lv5gj/BAgK5zwOqeNoDXUPbnLA1cEbjLHbJ7s5VVQORuSwjsEV9uLN4K 42 | OGxe7VhDSlVI/WCuQ1XH2QW7YHO3ViRUYlfLG1V/bT9vxQD41BX2ODsitgRBa2Z9 43 | vtXS5eB+ulX6Hu4lIoQpzrcep9iILyI+RwuAtjkJWHQSmzH3NgNX74aHcrbkVkaH 44 | AB43XjBurKerT+WnOdGscvHUA6xUxfBDqVn3EJSmUP96i5nXeLPjK7TPI5d7EDYA 45 | j2WuJH34G0YlTgNDELW+dilivUzVgzdOCMDggmWlTEwRPqlt2bGPZSLrqlYWAcgV 46 | V+ECggEBAKDKzKlWvkIb0EQXvacEtXU/sYwW6GPd8WF8/FkAluhdRqElVsARWvvX 47 | HIVpBZU4rpIVufm6jeABJSkkRmzU4Uan5glCC6qPUkRh4hIDuR6+J5iJMSLNUh2P 48 | UPCyCHkooArRApZJnR2b7QMg3BG+a8DxBA/Z4Oarfb4rINEbKKfH1JbvkkN5GjTt 49 | 8P/YI3hT2XC/3ei5HB13TXCzE4eSjH7FfX2bYE0yj7IKPxyBNjkziryUYWFrnagO 50 | hYt7iLL1PUiVfC1KdSZBc5WnBkj7vTMywn3fdevFsmLsdItGnqoar0MhREV0E/pK 51 | aiRtQ6hq3tb6uV9vlUlpDAzk3bpLiNg= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /test/install_cert.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | function setup { 4 | #create a self-signed cert 5 | cert_dir=$(mktemp -d /tmp/certs.XXXXXX) 6 | docker run -v "$cert_dir":/certs amouat/create-test-cert > /dev/null 2>/dev/null 7 | 8 | #start a registry on localhost 9 | docker stop test-docker-reg &> /dev/null || true 10 | docker rm test-docker-reg &> /dev/null || true 11 | docker run -v $cert_dir:/certs -p 5000 --name test-docker-reg \ 12 | -e REGISTRY_HTTP_ADDR=:5000 \ 13 | -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/ca.crt \ 14 | -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \ 15 | -d registry:2 > /dev/null 16 | 17 | local running_address=$(docker port test-docker-reg 5000) 18 | local mapped_port=${running_address##*:} 19 | full_reg_name=test-docker-reg:"$mapped_port" 20 | 21 | } 22 | 23 | function teardown { 24 | 25 | docker stop test-docker-reg &> /dev/null || true 26 | docker rm test-docker-reg &> /dev/null || true 27 | if [[ -n $cert_dir ]]; then 28 | rm -rf "$cert_dir" 29 | fi 30 | 31 | } 32 | 33 | function restart_docker_mac { 34 | 35 | if [[ "$(uname -s)" = "Darwin" ]]; then 36 | killall com.docker.osx.hyperkit.linux 37 | sleep 2 38 | run docker pull alpine:latest > /dev/null 39 | while [[ "$status" != 0 ]] 40 | do 41 | sleep 1 42 | run docker pull alpine:latest &> /dev/null 43 | done 44 | docker start test-docker-reg 45 | local running_address=$(docker port test-docker-reg 5000) 46 | local mapped_port=${running_address##*:} 47 | full_reg_name=test-docker-reg:"$mapped_port" 48 | fi 49 | } 50 | 51 | @test "install via file" { 52 | 53 | sudo ../reg-tool.sh install-cert --cert-file "$cert_dir"/ca.crt \ 54 | --reg-name "$full_reg_name" \ 55 | --add-host 0.0.0.0 test-docker-reg > /dev/null 56 | 57 | restart_docker_mac 58 | docker pull alpine:latest > /dev/null 59 | docker tag alpine:latest "$full_reg_name"/test-image > /dev/null 60 | docker push "$full_reg_name"/test-image > /dev/null 61 | 62 | } 63 | 64 | @test "install via URL" { 65 | 66 | # serve cert via nginx 67 | docker stop test-cert-server &> /dev/null || true 68 | docker rm test-cert-server &> /dev/null || true 69 | docker run -p 80 --name test-cert-server \ 70 | -v "$cert_dir"/ca.crt:/usr/share/nginx/html/ca.crt -d nginx 71 | 72 | sudo ../reg-tool.sh install-cert \ 73 | --cert-file http://$(docker port test-cert-server 80)/ca.crt \ 74 | --reg-name "$full_reg_name" \ 75 | --add-host 0.0.0.0 test-docker-reg > /dev/null 76 | restart_docker_mac 77 | 78 | docker stop test-cert-server > /dev/null 79 | docker rm test-cert-server > /dev/null 80 | docker pull alpine:latest > /dev/null 81 | docker tag alpine:latest "$full_reg_name"/test-image > /dev/null 82 | docker push "$full_reg_name"/test-image > /dev/null 83 | } 84 | 85 | @test "install via secret" { 86 | 87 | minikube start > /dev/null || true 88 | run kubectl cluster-info > /dev/null 89 | while [[ "$status" != 0 ]] 90 | do 91 | sleep 1 92 | run kubectl cluster-info > /dev/null 93 | done 94 | kubectl delete secret test-registry-cert &> /dev/null || true 95 | kubectl create secret generic test-registry-cert --from-file="$cert_dir"/ca.crt 96 | sudo ../reg-tool.sh install-cert \ 97 | --k8s-secret test-registry-cert \ 98 | --reg-name "$full_reg_name" \ 99 | --add-host 0.0.0.0 test-docker-reg > /dev/null 100 | restart_docker_mac 101 | 102 | docker pull alpine:latest > /dev/null 103 | docker tag alpine:latest "$full_reg_name"/test-image > /dev/null 104 | docker push "$full_reg_name"/test-image > /dev/null 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Registry Tooling 2 | 3 | Tools for working with Docker registries, especially those using self-signed 4 | certificates. 5 | 6 | Currently there are two features: 7 | 8 | - [configuring local clients](https://github.com/ContainerSolutions/registry-tooling#configuring-a-client-to-access-a-registry-with-a-self-signed-certificate) to access a registry secured with a self-signed 9 | cert 10 | - easy [installation of a secure Docker registry](https://github.com/ContainerSolutions/registry-tooling#installing-a-secure-reigstry-on-kubernetes) onto a Kubernetes cluster 11 | using a self-signed certificate 12 | 13 | ## Installation 14 | 15 | ``` 16 | $ git clone https://github.com/ContainerSolutions/registry-tooling.git 17 | ``` 18 | 19 | At the moment there is no install script, just run the `reg-tool.sh` script from 20 | the directory you downloaded it into. 21 | 22 | ## Configuring a Client to Access a Registry with a Self-signed Certificate 23 | 24 | If you have a registry running with a self-signed certificate, it can be a pain 25 | to provide access to external Docker clients, such as Docker for Mac running on 26 | a dev's laptop. The registry tool can quickly take care of installing the 27 | registry certificate and also (optionally) configuring /etc/hosts to make the registry 28 | address resolvable. For example, if there is registry called `test-docker-reg` 29 | available at 192.168.1.103: 30 | 31 | ``` 32 | $ sudo ./reg-tool.sh install-cert \ 33 | --cert-file ca.crt \ 34 | --reg-name test-docker-reg:5000 \ 35 | --add-host 192.168.1.103 test-docker-reg 36 | Installing certificate 37 | Assuming running Docker for Mac - adding certificate to Docker keychain 38 | 39 | Certificate added - restart Docker for Mac to take effect 40 | 41 | Exposing registry via /etc/hosts 42 | 497 43 | 442 44 | 45 | Successfully configured localhost 46 | ``` 47 | 48 | And now the following should work: 49 | 50 | ``` 51 | $ docker tag alpine:latest test-docker-reg:5000/test-image 52 | $ docker push test-docker-reg:5000/test-image 53 | The push refers to a repository [test-docker-reg:5000/test-image] 54 | 011b303988d2: Pushed 55 | latest: digest: sha256:1354db23ff5478120c980eca1611a51c9f2b88b61f24283ee8200bf9a54f2e5c size: 528 56 | ``` 57 | 58 | This works on both Linux and Mac hosts. When using Docker for Mac, the 59 | certificate will be added to the system keychain. 60 | 61 | Certificates can also be retrieved from URLs or a Kubernetes secret. 62 | 63 | If the registry address is already resolvable, omit the `--add-host` flag to 64 | prevent `/etc/hosts` being edited. 65 | 66 | ## Installing a Secure Registry on Kubernetes 67 | 68 | Whilst there is an existing [cluster addon to start a 69 | registry](https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/registry), 70 | it suffers from several flaws: 71 | 72 | - It does not use TLS. This means all transfers are unencrypted. 73 | - Each cluster node runs an instance of haproxy (the kube-registry-proxy image). 74 | - Another proxy has to be set-up to enable access from developer's machines 75 | 76 | Using this tool will: 77 | 78 | - Install a registry on the current cluster with a self-signed certificate. 79 | - Configure all nodes to access the registry via TLS. 80 | - Use NodePorts to avoid the need to run haproxy. 81 | - Support easy installation of the certificate on local clients (e.g. 82 | developer's latops). 83 | 84 | It will not currently configure a storage backend; please take a look at the 85 | config files to see how to do this. 86 | 87 | The script has been tested with 88 | [minikube](https://github.com/kubernetes/minikube) and GCE clusters. 89 | 90 | WARNING: This will do funky stuff like edit /etc/hosts. It will warn before 91 | doing this, but please be aware that it could break things. If you want to get a 92 | secure registry running on existing cluster already handling load, I suggest you 93 | look at what the scripts do and run the steps manually. 94 | 95 | ### Usage 96 | 97 | The script will target whichever cluster `kubectl` currently points at. 98 | Assuming your cluster is up-and-running, try: 99 | 100 | ``` 101 | $ ./reg-tool.sh install-k8s-reg 102 | ``` 103 | 104 | Once that completes, you should have running registry with certificates copied 105 | to all nodes and networking configured. You can then configure the local Docker 106 | daemon to access the registry with: 107 | 108 | ``` 109 | $ sudo ./reg-tool.sh install-cert --add-host 110 | ``` 111 | 112 | or, if using minikube: 113 | 114 | ``` 115 | $ sudo ./reg-tool.sh install-cert --add-host $(minikube ip) 116 | ``` 117 | 118 | 119 | This command should work on any Linux or Docker for Mac host whose kubectl is 120 | pointing at a cluster running a configured registry. We can then test with: 121 | 122 | 123 | ``` 124 | $ docker pull redis 125 | ... 126 | $ docker tag redis kube-registry.kube-system.svc.cluster.local:31000/redis 127 | $ docker push kube-registry.kube-system.svc.cluster.local:31000/redis 128 | ... 129 | $ kubectl run r1 --image kube-registry.kube-system.svc.cluster.local:31000/redis 130 | ``` 131 | 132 | Please note that it can sometimes take a few minutes for DNS to update. 133 | 134 | ## Minikube 135 | 136 | If you're using minikube, note that you can also use the Docker daemon in the VM 137 | to access the registry. Rather than using the script to install a certificate 138 | you can just do: 139 | 140 | ``` 141 | $ eval $(minikube docker-env) 142 | ``` 143 | 144 | If you do a `minikube stop` followed by a `minikube start`, you'll need to rerun 145 | `./reg-tool.sh` as `minikube start` will overwrite `/etc/hosts` and create new 146 | certs. 147 | 148 | ## Further Development 149 | 150 | Was this useful to you? Or would you like to see different features? 151 | 152 | Container Solutions are currently looking at developing tooling for working with 153 | images and registries on clusters. Please get in touch if you'd like to hear 154 | more or discuss ideas. 155 | 156 | - adrian.mouat@container-solutions.com 157 | - [@adrianmouat](https://twitter.com/adrianmouat) 158 | 159 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /reg-tool.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Turn on "strict mode" 4 | # http://redsymbol.net/articles/unofficial-bash-strict-mode/ 5 | # Not using -u as it upsets BATS :( 6 | set -eo pipefail 7 | unset CDPATH 8 | IFS=$'\n\t' 9 | 10 | function configure_nodes { 11 | echo 12 | echo "Tidying up any old registry jobs" 13 | kubectl delete job create-certs &> /dev/null || true 14 | 15 | echo 16 | echo "Creating new registry certificate" 17 | kubectl create -f k8s/create-certs.yaml &> /dev/null || true 18 | 19 | echo 20 | echo -n "Waiting for job to complete" 21 | while [[ $(kubectl get job create-certs \ 22 | -o go-template --template "{{.status.succeeded}}") != 1 ]] 23 | do 24 | sleep 1 25 | echo -n "." 26 | done 27 | 28 | echo 29 | echo "Copying certs to nodes" 30 | 31 | for job in $(kubectl get jobs -o go-template --template '{{range .items}}{{.metadata.name}} 32 | 33 | {{end}}') # blank line is important 34 | do 35 | if [[ $job = copy-certs* ]]; then 36 | kubectl delete job "$job" 37 | fi 38 | done 39 | tmp_file=$(mktemp) 40 | kubectl get nodes -o go-template-file --template ./k8s/copy-certs-templ.yaml > "$tmp_file" 41 | kubectl create -f "$tmp_file" 42 | rm "$tmp_file" 43 | 44 | echo 45 | echo "Removing any old registry and starting new one..." 46 | kubectl delete rc --namespace=kube-system kube-registry &> /dev/null || true 47 | kubectl create -f k8s/reg_controller.yaml 48 | kubectl delete svc --namespace=kube-system kube-registry &> /dev/null || true 49 | kubectl create -f k8s/reg_service.yaml 50 | 51 | #wait for cert to become available 52 | echo 53 | echo -n "Waiting for cert to become available" 54 | set +e 55 | kubectl get --namespace=kube-system secret registry-cert &> /dev/null 56 | local rc=$? 57 | while [[ $rc != 0 ]] 58 | do 59 | sleep 1 60 | echo -n "." 61 | kubectl get --namespace=kube-system secret registry-cert &>/dev/null 62 | rc=$? 63 | done 64 | set -e 65 | } 66 | 67 | function get_cert_from_k8s { 68 | local tmp_file="$1" 69 | 70 | base64_arg="-d" 71 | if "$on_mac"; then 72 | base64_arg="-D" 73 | fi 74 | 75 | set +e 76 | kubectl get --namespace="$k8s_secret_ns" secret "$k8s_secret" \ 77 | -o go-template --template '{{(index .data "ca.crt")}}' \ 78 | | exec base64 $base64_arg > "$tmp_file" 79 | local rc=$? 80 | if [[ $rc != 0 ]]; then 81 | echo "Registry certificate not found - expected it to be stored in the 82 | Kubernetes secret $k8s_secret in namespace $k8s_secret_ns" 83 | echo "Failed to configure host." 84 | exit 1 85 | fi 86 | set -e 87 | } 88 | 89 | function copy_cert { 90 | 91 | cert_file=$1 92 | 93 | if "$on_mac"; then 94 | 95 | echo "Assuming running Docker for Mac - adding certificate to Docker keychain" 96 | sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$cert_file" 97 | echo 98 | echo "Certificate added - restart Docker for Mac to take effect" 99 | 100 | else #on Linux 101 | 102 | echo "Adding certificate to local machine..." 103 | mkdir -p "/etc/docker/certs.d/${registry_host}" 104 | cp "$cert_file" "/etc/docker/certs.d/${registry_host}/ca.crt" 105 | fi 106 | } 107 | 108 | function add_to_etc_hosts { 109 | 110 | echo 111 | echo "Exposing registry via /etc/hosts" 112 | 113 | 114 | # sed would be a better choice than ed, but it wants to create a temp file :( 115 | # turned off stderr here, as ed likes to write to it even in success case 116 | 117 | if [[ -n "$add_host_ip" ]]; then 118 | printf "g/%s/d\nw\n" "$add_host_name" \ 119 | | ed /etc/hosts 2> /dev/null 120 | 121 | echo "$add_host_ip $add_host_name #added by secure-kube-registry" >> /etc/hosts 122 | else 123 | echo 124 | echo "Failed to find external address for cluster" >&2 125 | echo "Please set the IP address explicitly." 126 | echo "For example, if you're running minikube:" 127 | echo 128 | echo "$ sudo $0 install-cert" '--add-host $(minikube ip)' 129 | exit 2 130 | fi 131 | echo 132 | echo "Successfully configured localhost" 133 | return 0 134 | } 135 | 136 | function get_ip_from_k8s { 137 | 138 | add_host_ip="" 139 | local schedulable_nodes="" 140 | schedulable_nodes="$(kubectl get nodes -o template \ 141 | --template='{{range.items}}{{if not .spec.unschedulable}}{{range.status.addresses}}{{if eq .type "ExternalIP"}}{{.address}} {{end}}{{end}}{{end}}{{end}}')" 142 | 143 | for n in $schedulable_nodes 144 | do 145 | add_host_ip=$n 146 | break 147 | done 148 | 149 | if [[ -z "$add_host_ip" ]]; then 150 | echo 151 | echo "Failed to discover ip for registry." 152 | echo "Please specify explicitly with --add-host e.g:" 153 | echo 154 | echo " $0 --add-host 192.168.0.3 my-registry" 155 | exit 1 156 | fi 157 | } 158 | 159 | 160 | function install_k8s_registry { 161 | 162 | k8s_usage=$(cat </dev/null 2>&1 || { 345 | echo >&2 "Install curl to get certificates from URL" 346 | exit 1 347 | } 348 | echo "Retrieving certificate from $file_path" 349 | curl -sSL "$file_path" > "$tmp_file" 350 | else 351 | cp "$file_path" "$tmp_file" 352 | fi 353 | 354 | else 355 | if [[ -z "$k8s_secret_ns" ]]; then 356 | #test if secret in default ns or kube-system 357 | set +e 358 | kubectl get secret "$k8s_secret" --namespace=kube-system > /dev/null 359 | local rc=$? 360 | if [[ $rc == 0 ]]; then 361 | k8s_secret_ns="kube-system" 362 | else 363 | kubectl get secret "$k8s_secret" --namespace= > /dev/null 364 | rc=$? 365 | if [[ $rc == 0 ]]; then 366 | k8s_secret_ns= 367 | else 368 | echo "Cannot find secret $k8s_secret in kube-system or default namespace" 369 | exit 1 370 | fi 371 | fi 372 | set -e 373 | 374 | fi 375 | echo "Retrieving certificate from Kubernetes secret $k8s_secret" 376 | if [[ -n $k8s_secret_ns ]]; then 377 | echo "in namespace $k8s_secret_ns" 378 | fi 379 | get_cert_from_k8s "$tmp_file" 380 | fi 381 | 382 | echo "Installing certificate" 383 | copy_cert "$tmp_file" 384 | 385 | 386 | if [[ -n "$add_host_ip" ]]; then 387 | #probably put check here 388 | add_to_etc_hosts 389 | fi 390 | 391 | return $? 392 | } 393 | 394 | #start main 395 | 396 | default_host="kube-registry.kube-system.svc.cluster.local:31000" 397 | registry_host=$default_host 398 | registry_port='' #parsed from host later 399 | 400 | on_mac=false 401 | if [[ "$(uname -s)" = "Darwin" ]]; then 402 | on_mac=true 403 | fi 404 | 405 | #change to directory with script so we can reach deps 406 | #https://stackoverflow.com/questions/59895/can-a-bash-script-tell-which-directory-it-is-stored-in 407 | src_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 408 | cd "$src_dir" 409 | 410 | #process args 411 | 412 | args=$@ 413 | require_confirm=true 414 | file_path= 415 | k8s_secret="registry-cert" 416 | k8s_secret_set= 417 | k8s_secret_ns= 418 | add_host_ip= 419 | 420 | usage=$(cat <&2 478 | print_help 479 | exit 1 480 | ;; 481 | esac 482 | shift 483 | fi 484 | 485 | # No commands given 486 | print_help 487 | exit 1 488 | --------------------------------------------------------------------------------