From 6dc4839d74117c78e588e8c1ac7cdc1e03bdaceb Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Tue, 2 Apr 2019 18:07:21 +0200 Subject: [PATCH] app/registry: initial docker registry setup --- app/registry/prod.jsonnet | 240 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 app/registry/prod.jsonnet diff --git a/app/registry/prod.jsonnet b/app/registry/prod.jsonnet new file mode 100644 index 00000000..0b7fea56 --- /dev/null +++ b/app/registry/prod.jsonnet @@ -0,0 +1,240 @@ +local kube = import "../../kube/kube.libsonnet"; +local cm = import "../../cluster/kube/lib/cert-manager.libsonnet"; + +{ + local app = self, + local cfg = app.cfg, + cfg:: { + namespace: "registry", + domain: "k0.hswaw.net", + }, + + metadata(component):: { + namespace: cfg.namespace, + labels: { + "app.kubernetes.io/name": "registry", + "app.kubernetes.io/managed-by": "kubecfg", + "app.kubernetes.io/component": component, + }, + }, + + namespace: kube.Namespace(cfg.namespace), + + registryIssuer: cm.Issuer("registry-issuer") { + metadata+: app.metadata("registry-issuer"), + spec: { + selfSigned: {}, + }, + }, + authCertificate: cm.Certificate("auth") { + metadata+: app.metadata("auth"), + spec: { + secretName: "auth-internal", + duration: "43800h0m0s", // 5 years + issuerRef: { + name: app.registryIssuer.metadata.name, + }, + commonName: "auth.registry", + }, + }, + registryCertificate: cm.Certificate("registry") { + metadata+: app.metadata("registry"), + spec: { + secretName: "registry-internal", + duration: "43800h0m0s", // 5 years + issuerRef: { + name: app.registryIssuer.metadata.name, + }, + commonName: "registry.registry", + }, + }, + + registryConfig: kube.ConfigMap("registry-config") { + metadata+: app.metadata("registry-config"), + data: { + "config.yml": std.manifestYamlDoc({ + version: "0.1", + log: { + fields: { + service: "registry", + }, + }, + storage: { + cache: { + blobdescriptor: "inmemory", + }, + filesystem: { + rootdirectory: "/var/lib/registry", + }, + }, + http: { + addr: ":5000", + headers: { + "X-Content-Type-Options": ["nosniff"], + }, + tls: { + certificate: "/certs/tls.crt", + key: "/certs/tls.key", + }, + }, + health: { + storagedriver: { + enabled: true, + interval: "10s", + threshold: 3, + }, + }, + auth: { + token: { + realm: "https://registry.%s/auth" % [cfg.domain], + service: "my.docker.registry", + issuer: "registry.%s auth server" % [cfg.domain], + rootcertbundle: "/authcerts/tls.crt", + }, + }, + }), + }, + }, + + authConfig: kube.ConfigMap("auth-config") { + metadata+: app.metadata("auth-config"), + data: { + "auth_config.yml": std.manifestYamlDoc({ + server: { + addr: ":5001", + certificate: "/certs/tls.crt", + key: "/certs/tls.key", + }, + token: { + issuer: "registry.%s auth server" % [cfg.domain], + expiration: 900, + }, + users: { + # Password is specified as a BCrypt hash. Use `htpasswd -nB USERNAME` to generate. + "admin": { + password: "$2y$05$LO.vzwpWC5LZGqThvEfznu8qhb5SGqvBSWY1J3yZ4AxtMRZ3kN5jC", # badmin + }, + "test": { + password: "$2y$05$WuwBasGDAgr.QCbGIjKJaep4dhxeai9gNZdmBnQXqpKly57oNutya", # 123 + }, + }, + acl: [ + { + match: {account: "admin"}, + actions: ["*"], + comment: "Admin has full access to everything.", + }, + { + match: {account: "user"}, + actions: ["pull"], + comment: "User \"user\" can pull stuff.", + }, + ], + }), + } + }, + + authDeployment: kube.Deployment("auth") { + metadata+: app.metadata("auth"), + spec+: { + replicas: 1, + template+: { + spec+: { + volumes_: { + config: kube.ConfigMapVolume(app.authConfig), + certs: { + secret: { secretName: app.authCertificate.spec.secretName }, + }, + }, + containers_: { + auth: kube.Container("auth") { + image: "cesanta/docker_auth:1", + volumeMounts_: { + config: { mountPath: "/config" }, + certs: { mountPath: "/certs" }, + }, + }, + }, + }, + }, + }, + }, + authService: kube.Service("auth") { + metadata+: app.metadata("auth"), + target_pod:: app.authDeployment.spec.template, + spec+: { + type: "ClusterIP", + ports: [ + { name: "auth", port: 5001, targetPort: 5001, protocol: "TCP" }, + ], + } + }, + registryDeployment: kube.Deployment("docker-registry") { + metadata+: app.metadata("docker-registry"), + spec+: { + replicas: 1, + template+: { + spec+: { + volumes_: { + config: kube.ConfigMapVolume(app.registryConfig), + certs: { + secret: { secretName: app.registryCertificate.spec.secretName }, + }, + authcerts: { + secret: { secretName: app.authCertificate.spec.secretName }, + }, + }, + containers_: { + registry: kube.Container("docker-registry") { + image: "registry:2", + args: ["/config/config.yml"], + volumeMounts_: { + config: { mountPath: "/config" }, + certs: { mountPath: "/certs" }, + authcerts: { mountPath: "/authcerts" }, + }, + }, + }, + }, + }, + }, + }, + registryService: kube.Service("docker-registry") { + metadata+: app.metadata("docker-registry"), + target_pod:: app.registryDeployment.spec.template, + spec+: { + type: "ClusterIP", + ports: [ + { name: "registry", port: 5000, targetPort: 5000, protocol: "TCP" }, + ], + } + }, + registryIngress: kube.Ingress("registry") { + metadata+: app.metadata("registry") { + annotations+: { + "kubernetes.io/tls-acme": "true", + "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod", + "nginx.ingress.kubernetes.io/backend-protocol": "HTTPS", + }, + }, + spec+: { + tls: [ + { + hosts: ["registry.%s" % [cfg.domain]], + secretName: "registry-tls", + }, + ], + rules: [ + { + host: "registry.%s" % [cfg.domain], + http: { + paths: [ + { path: "/auth", backend: app.authService.name_port }, + { path: "/", backend: app.registryService.name_port }, + ] + }, + } + ], + }, + }, +}