├── .gitignore ├── LICENSE ├── README.md ├── auth ├── config │ ├── auth_config.yml │ ├── ldap_certificates │ │ └── COPY_CERTIFICATES_HERE_THAT_ARE_NEEDED_FOR_AUTHENTICATION_AGAINST_LDAP │ ├── ldap_password.txt │ └── reference.yml └── start.sh ├── certs ├── README.md ├── auth.crt ├── auth.key ├── registry.crt └── registry.key ├── docker-compose.yml ├── docs ├── setup.graphml └── setup.png ├── ldap ├── Dockerfile ├── setup-ldap-schema.ldif ├── setup-ldap-schema.sh ├── slapd.sh └── supervisord.conf └── registry └── conf └── config.yml /.gitignore: -------------------------------------------------------------------------------- 1 | registry/storage/* 2 | auth/logs 3 | auth/config/ldap_certificates/* 4 | auth/config/config.yml.custom 5 | *~ 6 | -------------------------------------------------------------------------------- /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 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker Registry Setup 2 | 3 | This project is intended for people like me who need to get their hands on a 4 | piece of technology before they can fully grasp it. 5 | 6 | The purpose of this project is rather educational. I'll show you how you can 7 | setup a docker registry v2 and an authorization server with an LDAP backend. 8 | In fact, everything is already setup for you to run. There's a docker container 9 | for the registry, the JWT auth server and the LDAP server. Feel free to connect 10 | to your company LDAP if you want by making adjustments to the auth server's 11 | config file (`auth/config/config.yml`). Just like that you can replace this 12 | setup piece by piece to suite your needs. 13 | 14 | Here's a graphic showing all the containers and how they talk to each other: 15 | 16 | ![](https://raw.githubusercontent.com/kwk/docker-registry-setup/master/docs/setup.png) 17 | 18 | 1. Attempt to begin a push/pull operation with the registry. 19 | 2. If the registry requires authorization it will return a 401 Unauthorized HTTP response with information on how to authenticate. 20 | 3. The registry client makes a request to the authorization service for a Bearer token. 21 | 4. The authorization server makes a request to the LDAP server to check if a user exists. We use a service account to connect to the LDAP server. 22 | 5. The LDAP server returns an answer to the user lookup. 23 | 6. The authorization service returns an opaque Bearer token representing the client's authorized access. 24 | 7. The client retries the original request with the Bearer token embedded in the request's Authorization header. 25 | 8. The Registry authorizes the client by validating the Bearer token and the claim set embedded within it and begins the push/pull session as usual. 26 | 27 | [Here](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md) 28 | you can read more about the Docker v2 registry authorization process. 29 | 30 | # How are authentication and authorization configured 31 | 32 | **NOTE** Remember, that *authentication* ensures that you are who you claim t 33 | be. *Authorization* on the other hand defines rules of what somebody is 34 | (dis)allowed to do. 35 | 36 | The auth server is configured to try all authentication methods that 37 | have been specified in `auth/config/config.yml`. Currently LDAP and a static 38 | list of users/passwords are configured 39 | 40 | These password combinations are defined statically: 41 | 42 | * admin:badmin (can push and pull) 43 | * test:123 (can only pull) 44 | 45 | I've included an LDAP server in the `docker-compose.yml` that is also used for 46 | authentication. This is the LDAP hierarchy: 47 | 48 | ``` 49 | com 50 | |_example 51 | | 52 | |_philosophs 53 | | |_schopenhauer 54 | | |_kant 55 | |_musicians 56 | | |_mozart 57 | | |_bach 58 | |_it 59 | |_serviceaccount 60 | ``` 61 | 62 | (This hierarchy is described here: `ldap/setup-ldap-schema.ldif`.) 63 | 64 | All musicians (`mozart` and `bach`) are usernames that are authorized to login 65 | using the password `password` and they can all push and pull images to or from 66 | the registry. The philosophs (`schopenhauer` and `kant`) are not used and will 67 | not function with the current LDAP search base (see 68 | `base: "ou=musicians,dc=example,dc=com"` in `auth/config/config.yml`). 69 | 70 | I use the `serviceaccount` username to connect to bind to LDAP from the auth 71 | server. It 72 | 73 | **Notice** that on a successful second pull or push you won't have to enter your 74 | credentials again because they have been saved here: `~/.docker/config.json`. 75 | Remove this file if you want to force another prompt for username and password. 76 | 77 | # Preparation 78 | 79 | **IMPORTANT** Read these instructions to get up and running with your own 80 | already configured docker registry v2 deployment. 81 | 82 | ## Configure docker deamon 83 | 84 | These instructions only need to be executed once. For the purpose of demonstation we 85 | will be running a registry on `localhost` and by default we must inform our 86 | docker client about any insecure registry that we want to be using. Here's how 87 | it works: 88 | 89 | * Make sure you have docker > 1.8 as well as docker-compose installed. 90 | * Ensure your `DOCKER_OPTS` contains this option: `--insecure-registry 0.0.0.0:5000`. 91 | On an Ubuntu 14.04 you can find this option in your `/etc/default/docker` file. 92 | * Restart your docker service: `service docker restart`. 93 | 94 | # How to run 95 | 96 | ```bash 97 | # Clone the repository 98 | git clone https://github.com/kwk/docker-registry-setup.git 99 | 100 | # Navigate inside 101 | cd docker-registry-setup 102 | 103 | # Fire up the registry and the auth server as containers 104 | # Notice that the docker registry is configured with a persistent storage volume 105 | # from the docker host, hence --force-recreate will not wipe this storage for you. 106 | docker-compose up -d --force-recreate 107 | 108 | # Pull an image from the offical docker hub that we want push to our own secured registry 109 | docker pull busybox 110 | 111 | # Tag the image so that it can be pushed to our local registry 112 | docker tag busybox 0.0.0.0:5000/anyuser/busybox 113 | ``` 114 | 115 | Okay, up until know we haven't pushed or pulled from our local registry. It is 116 | now time to change this: 117 | 118 | ```bash 119 | # First ensure we haven't stored any credentials: 120 | mv -b ~/.docker/config.json ~/.docker/config.json.orig 121 | 122 | # Push the image 123 | docker push 0.0.0.0:5000/anyuser/busybox 124 | ``` 125 | 126 | And voila, you'll be prompted for a username and a password. Let's use the 127 | username `mozart` (from the *musicians* organization unit in LDAP) and the 128 | password `password`. The email address doesn't matter this much. 129 | 130 | ``` 131 | The push refers to a repository [0.0.0.0:5000/anyuser/busybox] (len: 1) 132 | d7057cb02084: Image push failed 133 | 134 | Please login prior to push: 135 | Username: mozart 136 | Password: 137 | Email: mozart@example.com 138 | WARNING: login credentials saved in /home/YOU/.docker/config.json 139 | Login Succeeded 140 | The push refers to a repository [0.0.0.0:5000/anyuser/busybox] (len: 1) 141 | d7057cb02084: Image successfully pushed 142 | cfa753dfea5e: Image successfully pushed 143 | latest: digest: sha256:15eda5ab78f31658ab922650eebe9da9ccc6c16462d5ef0bfd6d9f29b8800569 size: 2743 144 | ``` 145 | 146 | ## Test that LDAP auth is working 147 | 148 | This will connect to the LDAP and query all information below the base (`-b`). 149 | The user that is used to authenticate is called `YOUR_SERVICE_ACCOUNT` 150 | and the password is taken from the file `./auth/config/ldap_password.txt`. But 151 | since most editors append a newline (`\n`) or carriage return (`\r`) we first 152 | remove those characters. The user `YOUR_SERVICE_ACCOUNT` is a service account, 153 | but if you don't have one you can also try to login with your own email address 154 | (`-D FIRSTNAME.LASTNAME@YOUR_COMPANY.com`). 155 | 156 | ```bash 157 | LDAP_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' dockerregistrysetup_ldap_1) 158 | ldapsearch -v \ 159 | -H ldap://$LDAP_IP:389 \ 160 | -x \ 161 | -D "uid=serviceaccount,ou=it,dc=example,dc=com" \ 162 | -b "ou=musicians,dc=example,dc=com" \ 163 | -w password 164 | ``` 165 | 166 | To find an entry based on a user's email address execute this command: 167 | 168 | ```bash 169 | LDAP_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' dockerregistrysetup_ldap_1) 170 | ldapsearch -v \ 171 | -H ldap://$LDAP_IP:389 \ 172 | -x \ 173 | -D "uid=serviceaccount,ou=it,dc=example,dc=com" \ 174 | -b "ou=musicians,dc=example,dc=com" \ 175 | -w password \ 176 | "(&(mail=mozart@example.com)(objectClass=person))" 177 | ``` 178 | 179 | and appropriately replace `FIRSTNAME.LASTNAME@YOUR_COMPANY.com` with your own 180 | email address. 181 | 182 | ## How to use your own LDAP as your authentication backend... 183 | 184 | 1. Chances are that your own LDAP server requires you to have certificates 185 | installed on the machine that binds to LDAP. Simply copy those certificates to 186 | `auth/config/ldap_certificates/`. I've [modified the auth container](https://github.com/kwk/docker-registry-setup/blob/master/auth/start.sh#L4) a bit by 187 | introducing a start script that automatically searches for files in that 188 | that directory and updates the cert store of the container on every start. 189 | 2. Copy the `auth/config/auth_config.yml` to `auth/config/auth_config.yml.custom` and 190 | adjust all the settings inside to match the LDAP configuration that you have 191 | validated above. The file `auth/config/auth_config.yml.custom` will be loaded instead 192 | of `auth/config/auth_config.yml` whenever it is present. 193 | 3. Put the password for the service account in this file: 194 | `auth/config/ldap_password.txt`. 195 | 4. Restart the registry and auth server: `docker-compose up -d --force-recreate` 196 | 5. Try pushing an image to the registry and login with your LDAP credentials. 197 | 198 | # Test the auth server 199 | 200 | Replace `USERNAME` and `PASSWORD` below with credentials of somebody who wants 201 | to authenticate against LDAP (eg. `mozart` and `password`). You should get an 202 | `HTTP 200 OK` response containing a JSON Web `token` if everything worked 203 | correctly. 204 | 205 | ``` 206 | curl -H "Authorization: Basic $(echo "USERNAME:PASSWORD" | base64)" -vk "https://127.0.0.1:5001/auth?service=Docker%20registry&scope=registry:catalog:*" 207 | ``` 208 | 209 | # Manual token-based workflow to list repositories 210 | 211 | You can skip this section if you're not interested in how a token can be 212 | requested manually to list the repositories inside a registry. 213 | 214 | ```bash 215 | # This is the operation we want to perform on the registry 216 | registryURL=https://127.0.0.1:5000/v2/_catalog 217 | 218 | # Save the response headers of our first request to the registry to get the Www-Authenticate header 219 | respHeader=$(tempfile); 220 | curl -k --dump-header $respHeader $registryURL 221 | 222 | # Extract the realm, the service, and the scope from the Www-Authenticate header 223 | wwwAuth=$(cat $respHeader | grep "Www-Authenticate") 224 | realm=$(echo $wwwAuth | grep -o '\(realm\)="[^"]*"' | cut -d '"' -f 2) 225 | service=$(echo $wwwAuth | grep -o '\(service\)="[^"]*"' | cut -d '"' -f 2) 226 | scope=$(echo $wwwAuth | grep -o '\(scope\)="[^"]*"' | cut -d '"' -f 2) 227 | 228 | # Build the URL to query the auth server 229 | authURL="$realm?service=$service&scope=$scope" 230 | 231 | # Query the auth server to get a token 232 | token=$(curl -ks -H "Authorization: Basic $(echo -n "mozart:password" | base64)" "$authURL") 233 | 234 | # Get the bare token from the JSON string: {"token": "...."} 235 | token=$(echo $token | jq .token | tr -d '"') 236 | 237 | # Query the registry again, but this time with a bearer token 238 | curl -vk -H "Authorization: Bearer $token" $registryURL 239 | ``` 240 | 241 | As a result you should get a list of repositories in your registry. If you have 242 | pushed only the busybox image from above to your registry you should see an HTTP 243 | body like this: 244 | 245 | ```json 246 | {"repositories":["anyuser/busybox"]} 247 | ``` 248 | 249 | # Plans 250 | 251 | - [ ] Integrate a frontend 252 | 253 | Have fun! 254 | -------------------------------------------------------------------------------- /auth/config/auth_config.yml: -------------------------------------------------------------------------------- 1 | # . See reference.yml for explanation for explanation of all options. 2 | # 3 | # auth: 4 | # token: 5 | # realm: "https://127.0.0.1:5001/auth" 6 | # service: "Docker registry" 7 | # issuer: "Acme auth server" 8 | # rootcertbundle: "/path/to/server.pem" 9 | 10 | server: 11 | addr: ":5001" 12 | certificate: "/certs/auth.crt" 13 | key: "/certs/auth.key" 14 | 15 | token: 16 | issuer: "Acme auth server" # Must match issuer in the Registry config. 17 | expiration: 900 18 | 19 | # LDAP authentication. 20 | # Authentication is performed by first binding to the server, looking up the user entry 21 | # by using the specified filter, and then re-binding using the matched DN and the password provided. 22 | ldap_auth: 23 | addr: "ldap:389" 24 | #tls: true 25 | # In case bind DN and password is required for querying user information, 26 | # specify them here. Plain text password is read from the file. 27 | bind_dn: "uid=serviceaccount,ou=it,dc=example,dc=com" 28 | # Make sure you remove newlines and carriage returns from the password file. 29 | bind_password_file: /tmp/ldap_password.txt.clean 30 | # User query settings. ${account} is expanded from auth request 31 | base: "ou=musicians,dc=example,dc=com" 32 | filter: "(&(uid=${account})(objectClass=organizationalPerson))" 33 | 34 | users: 35 | # Password is specified as a BCrypt hash. Use htpasswd -B to generate. 36 | "admin": 37 | password: "$2y$05$LO.vzwpWC5LZGqThvEfznu8qhb5SGqvBSWY1J3yZ4AxtMRZ3kN5jC" # badmin 38 | "test": 39 | password: "$2y$05$WuwBasGDAgr.QCbGIjKJaep4dhxeai9gNZdmBnQXqpKly57oNutya" # 123 40 | 41 | acl: 42 | # Admin has full access to everything. 43 | - match: {account: "admin"} 44 | actions: ["*"] 45 | 46 | # User "user" can pull stuff. 47 | - match: {account: "test"} 48 | actions: ["pull"] 49 | 50 | # This will allow authenticated users to pull/push 51 | - match: 52 | account: /.+/ 53 | actions: ['*'] 54 | 55 | # The user "serviceaccount" (from LDAP) may not perform any docker actions 56 | # like push or pull. 57 | - match: {account: "serviceaccount"} 58 | actions: [] 59 | -------------------------------------------------------------------------------- /auth/config/ldap_certificates/COPY_CERTIFICATES_HERE_THAT_ARE_NEEDED_FOR_AUTHENTICATION_AGAINST_LDAP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwk/docker-registry-setup/101aa6e8cba1c58174cceee549383efcdfb0fb15/auth/config/ldap_certificates/COPY_CERTIFICATES_HERE_THAT_ARE_NEEDED_FOR_AUTHENTICATION_AGAINST_LDAP -------------------------------------------------------------------------------- /auth/config/ldap_password.txt: -------------------------------------------------------------------------------- 1 | password 2 | -------------------------------------------------------------------------------- /auth/config/reference.yml: -------------------------------------------------------------------------------- 1 | # This config lists all the possible config options. 2 | # 3 | # To configure Docker Registry to talk to this server, put the following in the registry config file: 4 | # 5 | # auth: 6 | # token: 7 | # realm: "https://127.0.0.1:5001/auth" 8 | # service: "Docker registry" 9 | # issuer: "Acme auth server" 10 | # rootcertbundle: "/path/to/server.pem" 11 | 12 | server: # Server settings. 13 | # Address to listen on. 14 | addr: ":5001" 15 | # TLS certificate and key. 16 | certificate: "/path/to/server.pem" 17 | key: "/path/to/server.key" 18 | 19 | token: # Settings for the tokens. 20 | issuer: "Acme auth server" # Must match issuer in the Registry config. 21 | expiration: 900 22 | # It is possible configure a different certificate for tokens. 23 | # If not specified, server certificate is used. 24 | # certificate: "..." 25 | # key: "..." 26 | 27 | # Authentication methods. All are tried, any one returning success is sufficient. 28 | # At least one must be configured. If you want an unauthenticated public setup, 29 | # configure static user map with anonymous access. 30 | 31 | # Static user map. 32 | users: 33 | # Password is specified as a BCrypt hash. Use htpasswd -B to generate. 34 | "admin": 35 | password: "$2y$05$LO.vzwpWC5LZGqThvEfznu8qhb5SGqvBSWY1J3yZ4AxtMRZ3kN5jC" # badmin 36 | "test": 37 | password: "$2y$05$WuwBasGDAgr.QCbGIjKJaep4dhxeai9gNZdmBnQXqpKly57oNutya" # 123 38 | "": {} # Allow anonymous (no "docker login") access. 39 | 40 | # Google authentication. 41 | # ==! NB: DO NOT ENTER YOUR GOOGLE PASSWORD AT "docker login". IT WILL NOT WORK. 42 | # Instead, Auth server maintains a database of Google authentication tokens. 43 | # Go to the server's port with you browser and follow the "Login with Google account" link. 44 | # Once signed in, you will get a throw-away password which you can use for Docker login. 45 | google_auth: 46 | domain: "example.com" # Optional. If set, only logins fromt his domain are accepted. 47 | # client_id and client_secret for API access. Required. 48 | # Follow instructions here: https://developers.google.com/identity/sign-in/web/devconsole-project 49 | # NB: Make sure JavaScript origins are configured correcly. 50 | client_id: "1223123456-somethingsomething.apps.googleusercontent.com" 51 | # Either client_secret or client_secret_file is required. Use client_secret_file if you don't 52 | # want to have sensitive information checked in. 53 | # client_secret: "verysecret" 54 | client_secret_file: "/path/to/client_secret.txt" 55 | # Where to store server tokens. Required. 56 | token_db: "/somewhere/to/put/google_tokens.ldb" 57 | # How long to wait when talking to Google servers. Optional. 58 | http_timeout: 10 59 | 60 | # LDAP authentication. 61 | # Authentication is performed by first binding to the server, looking up the user entry 62 | # by using the specified filter, and then re-binding using the matched DN and the password provided. 63 | ldap_auth: 64 | addr: "ldap.example.com:389" 65 | tls: true 66 | # In case bind DN and password is required for querying user information, 67 | # specify them here. Plain text password is read from the file. 68 | bind_dn: 69 | bind_password_file: 70 | # User query settings. ${account} is expanded from auth request 71 | base: "o=example.com" 72 | filter: "(&(uid=${account})(objectClass=person))" 73 | 74 | # ACL specifies who can do what. If the match section of an entry matches the 75 | # request, the set of allowed actions will be applied to the token request 76 | # and a ticket will be issued only for those of the requested actions that are 77 | # allowed by the rule. 78 | # * It is possible to match on user's name ("account"), subject type ("type") 79 | # and name ("name"; for type=repository which, at the timeof writing, is the 80 | # only known subject type, this is the image name). 81 | # * Matches are evaluated as shell file name patterns ("globs") by default, 82 | # so "foobar", "f??bar", "f*bar" are all valid. For even more flexibility 83 | # match patterns can be evaluated as regexes by enclosing them in //, e.g. 84 | # "/(foo|bar)/". 85 | # * ACL is evaluated in the order it is defined until a match is found. 86 | # * Empty match clause matches anything, it only makes sense at the end of the 87 | # list and can be used as a way of specifying default permissions. 88 | # * Empty actions set means "deny everything". Thus, a rule with `actions: []` 89 | # is in effect a "deny" rule. 90 | # * A special set consisting of a single "*" action means "allow everything". 91 | # * If no match is found the default is to deny the request. 92 | # 93 | # You can use the following variables from the ticket request in any field: 94 | # * ${account} - the account name, currently the same as authenticated user's name. 95 | # * ${service} - the service name, specified by auth.token.service in the registry config. 96 | # * ${type} - the type of the entity, normally "repository". 97 | # * ${name} - the name of the repository (i.e. image), e.g. centos. 98 | acl: 99 | # Admin has full access to everything. 100 | - match: {account: "admin"} 101 | actions: ["*"] 102 | # User "test" has full access to test-* images but nothing else. 103 | - match: {account: "test", name: "test-*"} 104 | actions: ["*"] 105 | - match: {account: "test"} 106 | actions: [] 107 | # All logged in users can pull all images. 108 | - match: {account: "/.+/"} 109 | actions: ["pull"] 110 | # All logged in users can push all images that are in a namespace beginning with their name 111 | - match: {account: "/.+/", name: "${account}/*"} 112 | actions: ["*"] 113 | # Anonymous users can pull "hello-world". 114 | - match: {account: "", name: "hello-world"} 115 | actions: ["pull"] 116 | # Access is denied by default. 117 | -------------------------------------------------------------------------------- /auth/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copy over certificates to correct place and update certificate storage 4 | find "/config/ldap_certificates" -type f -exec cp -fv {} /usr/local/share/ca-certificates/ \; 5 | update-ca-certificates 6 | 7 | # Replace newline and carriage returns in password file 8 | cat /config/ldap_password.txt | tr -d '\r\n' > /tmp/ldap_password.txt.clean 9 | 10 | # If we see a custom config file, we load that instead of the default one 11 | CONF_PATH=/config/auth_config.yml 12 | if [ -f $CONF_PATH.custom ]; then 13 | CONF_PATH=$CONF_PATH.custom 14 | fi 15 | 16 | # Start the auth server 17 | /auth_server -v=5 -alsologtostderr=true -log_dir=/logs $CONF_PATH 18 | -------------------------------------------------------------------------------- /certs/README.md: -------------------------------------------------------------------------------- 1 | # Creation of example certificates 2 | 3 | **NOTE:** You should replace these files with your own!!! 4 | 5 | # Certificate and key for the registry 6 | 7 | The `registry.crt` and `registry.key` files have been created using this command: 8 | 9 | ``` 10 | openssl req -newkey rsa:4096 -nodes -sha256 -keyout registry.key -x509 -days 365 -out registry.crt 11 | Generating a 4096 bit RSA private key 12 | ............................................................................................++ 13 | ........................................................................................++ 14 | writing new private key to 'registry.key' 15 | ----- 16 | You are about to be asked to enter information that will be incorporated 17 | into your certificate request. 18 | What you are about to enter is what is called a Distinguished Name or a DN. 19 | There are quite a few fields but you can leave some blank 20 | For some fields there will be a default value, 21 | If you enter '.', the field will be left blank. 22 | ----- 23 | Country Name (2 letter code) [AU]:DE 24 | State or Province Name (full name) [Some-State]:Example State 25 | Locality Name (eg, city) []:Example City 26 | Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Company 27 | Organizational Unit Name (eg, section) []:Example Organization Unit 28 | Common Name (e.g. server FQDN or YOUR name) []:registry.example.com 29 | Email Address []:admin@registry.example.com 30 | ``` 31 | 32 | # Certificate and key for the auth server 33 | 34 | The `auth.crt` and `auth.key` files have been created using this command: 35 | 36 | ``` 37 | openssl req -newkey rsa:4096 -nodes -sha256 -keyout auth.key -x509 -days 365 -out auth.crt 38 | Generating a 4096 bit RSA private key 39 | ................................................................................................................................................................................................................++ 40 | ........................................................................++ 41 | writing new private key to 'auth.key' 42 | ----- 43 | You are about to be asked to enter information that will be incorporated 44 | into your certificate request. 45 | What you are about to enter is what is called a Distinguished Name or a DN. 46 | There are quite a few fields but you can leave some blank 47 | For some fields there will be a default value, 48 | If you enter '.', the field will be left blank. 49 | ----- 50 | Country Name (2 letter code) [AU]:DE 51 | State or Province Name (full name) [Some-State]:Example State 52 | Locality Name (eg, city) []:Example City 53 | Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Company 54 | Organizational Unit Name (eg, section) []:Example Organizational Unit 55 | Common Name (e.g. server FQDN or YOUR name) []:auth.example.com 56 | Email Address []:admin@auth.example.com 57 | ``` 58 | 59 | # How to list the contents of one of the certificates 60 | 61 | ```bash 62 | openssl x509 -in registry.crt -text 63 | ``` 64 | 65 | Output 66 | 67 | ``` 68 | Certificate: 69 | Data: 70 | Version: 3 (0x2) 71 | Serial Number: 15377324996609959013 (0xd5673b9ca2abe465) 72 | Signature Algorithm: sha256WithRSAEncryption 73 | Issuer: C=DE, ST=Example State, L=Example City, O=Example Company, OU=Example Organization Unit, CN=registry.example.com/emailAddress=admin@registry.example.com 74 | Validity 75 | Not Before: Oct 26 11:02:58 2015 GMT 76 | Not After : Oct 25 11:02:58 2016 GMT 77 | Subject: C=DE, ST=Example State, L=Example City, O=Example Company, OU=Example Organization Unit, CN=registry.example.com/emailAddress=admin@registry.example.com 78 | Subject Public Key Info: 79 | Public Key Algorithm: rsaEncryption 80 | Public-Key: (4096 bit) 81 | Modulus: 82 | 00:b3:90:24:96:67:de:56:aa:e3:b5:7d:27:5d:34: 83 | 4d:ce:60:bd:cf:9b:68:9e:af:e6:89:6d:95:74:9e: 84 | 3e:c6:27:8f:b6:34:52:ba:8b:9e:02:dc:a6:7c:a9: 85 | 84:6b:40:e1:ad:5b:c0:19:f4:8d:3d:81:76:2d:e9: 86 | f1:2f:d4:20:7d:50:15:6d:cb:b6:cd:93:eb:f7:d2: 87 | 9c:99:90:1b:b6:99:d8:ad:a5:7a:df:92:2f:ab:8e: 88 | b8:04:a9:cc:34:7f:d0:21:6a:46:89:a0:d5:2b:46: 89 | f8:41:4a:ee:2a:d7:57:04:a1:33:c8:3f:fd:a4:10: 90 | 81:1b:5b:5b:91:c9:0e:0c:91:0e:ea:fe:36:2e:f3: 91 | c7:be:01:2f:f4:fc:b0:ac:57:3b:d2:93:a8:0c:ad: 92 | 23:81:07:71:ef:3a:7e:6f:a4:52:c3:dc:ba:7e:db: 93 | 99:3c:c5:e0:66:88:8d:d2:f6:29:6c:a5:ac:9c:ba: 94 | a7:dd:2d:a0:8b:ad:54:b2:ff:a0:c6:26:90:15:0c: 95 | f9:2f:f8:d9:80:27:5a:52:08:8e:eb:84:5d:24:fe: 96 | ad:05:e9:c2:6e:e2:f2:03:ce:fc:2d:37:7e:cf:c5: 97 | ec:6d:45:d1:05:ed:97:11:f9:6b:89:66:dd:cc:4c: 98 | fd:b7:18:71:be:f5:c7:ac:e1:6a:a5:6a:78:ab:66: 99 | 15:0e:65:6b:08:47:8b:06:31:99:ab:bb:70:50:8e: 100 | 2f:a9:d6:9a:86:39:c8:79:ef:b6:64:d6:00:2b:8d: 101 | 79:c2:c5:c6:6f:02:5b:50:56:64:4e:7e:f4:74:63: 102 | 4f:80:6d:b2:55:13:4e:95:93:1e:66:1b:28:9c:6c: 103 | 6b:1c:62:63:fb:9a:8a:ed:08:c8:e0:5c:04:f3:dd: 104 | bb:c0:c5:d2:54:23:b8:bd:aa:95:30:62:ff:27:68: 105 | 41:bb:68:be:5b:f8:69:ef:3e:6f:81:fb:08:a4:f7: 106 | fb:07:82:c9:53:09:d3:ae:48:02:47:db:ef:60:b1: 107 | d7:be:6d:c1:d1:2d:ec:50:27:b2:29:9e:43:b4:e6: 108 | 2a:bb:99:23:1b:4b:27:89:c4:b8:64:30:33:a4:3b: 109 | b4:a1:fb:65:7b:ff:50:32:0e:68:ea:de:e2:5f:b1: 110 | 11:e3:3c:e9:b2:70:aa:7f:6e:7c:01:0d:00:f9:f9: 111 | 02:65:fc:84:03:aa:78:66:16:04:ae:31:ba:02:bf: 112 | 3c:8c:f6:2b:0b:ec:a5:e2:f9:eb:9a:ce:31:cc:17: 113 | 3e:49:65:39:77:94:68:60:d8:56:5e:61:4d:5b:af: 114 | 12:1d:f8:b8:7b:a5:32:0b:99:c4:ba:cb:d3:b4:2c: 115 | 93:97:b9:fc:96:85:d8:27:0c:d2:9c:81:4e:85:70: 116 | f0:a0:69 117 | Exponent: 65537 (0x10001) 118 | X509v3 extensions: 119 | X509v3 Subject Key Identifier: 120 | 1C:1B:FC:0C:39:36:72:76:48:06:B0:90:26:F7:E3:E4:5D:1C:3D:14 121 | X509v3 Authority Key Identifier: 122 | keyid:1C:1B:FC:0C:39:36:72:76:48:06:B0:90:26:F7:E3:E4:5D:1C:3D:14 123 | 124 | X509v3 Basic Constraints: 125 | CA:TRUE 126 | Signature Algorithm: sha256WithRSAEncryption 127 | 8e:d2:18:07:b1:f9:f1:4d:60:45:98:e0:a5:64:8e:77:4d:3d: 128 | fd:31:3f:14:2a:bd:35:c9:f5:93:a8:00:63:05:54:41:44:6c: 129 | fe:f0:ab:e8:04:b8:b3:58:e2:6f:dc:63:58:92:63:bb:6a:cc: 130 | 2d:83:71:00:17:87:91:d5:24:88:11:8e:47:d0:65:e9:16:c1: 131 | fe:92:e2:89:6d:56:f0:69:33:34:c3:e2:1f:57:00:6f:58:3c: 132 | 61:2f:a4:bf:74:93:5f:f4:72:2e:59:61:19:58:00:0c:13:0c: 133 | a4:ad:2a:81:b5:78:4f:d2:ed:3d:4c:80:a8:65:66:66:95:9f: 134 | 5a:9f:a9:85:05:2c:4b:e5:cb:74:e6:a3:4c:3f:2b:4f:cf:f9: 135 | 53:b2:a0:11:b0:55:d4:7a:55:30:00:d8:a9:30:95:f1:06:58: 136 | 00:03:96:c5:cc:d1:4e:b1:f8:57:87:79:d0:b1:ce:bb:95:27: 137 | 5a:96:d1:fb:4b:15:5e:60:37:ab:1d:41:4b:c2:f7:13:2a:c0: 138 | bb:0f:b8:b9:1f:16:28:80:76:96:1f:7c:da:b4:d8:9e:ed:2f: 139 | e7:80:e7:63:bc:4d:e4:2a:20:3c:c4:cc:34:8a:cc:8f:c5:0a: 140 | c4:ca:90:e6:32:af:b6:bd:2a:74:86:ce:72:3c:f0:01:69:15: 141 | 57:41:11:4e:55:d1:26:83:9b:7c:f4:ad:67:bb:af:4a:43:37: 142 | 4f:94:93:92:00:f2:08:b8:65:18:4a:db:0f:06:2a:b7:e2:4d: 143 | 2d:b0:62:9c:45:4a:9d:8d:b3:25:d0:99:c7:ed:21:e0:33:4b: 144 | dc:3e:15:77:79:54:ae:0c:31:1b:1d:d6:8f:7c:1e:0f:70:6c: 145 | 96:6f:3d:fa:60:db:a5:3e:a9:3a:bd:ec:2e:d1:49:8f:ec:d2: 146 | 2c:05:e6:55:8d:55:57:b8:a6:b3:7c:8a:a8:a1:b5:11:50:21: 147 | db:7d:f9:cb:24:db:e8:20:03:eb:ca:ac:5f:14:79:ad:e6:ff: 148 | 1e:d4:1e:35:6c:0f:15:b4:b8:c2:ab:40:2b:e6:25:a4:14:1b: 149 | 02:e7:16:27:a8:3a:6f:5f:79:96:11:b3:4a:77:6d:fc:cd:4d: 150 | d0:16:7f:c3:0b:9e:fa:d6:0c:4d:bd:92:dd:43:54:7f:b7:28: 151 | 27:5b:14:26:72:d2:55:66:6c:1c:e0:ac:1e:11:41:d2:8b:8c: 152 | 0e:c6:97:d8:b2:c1:5e:05:8f:66:55:d5:d0:b0:38:de:16:a4: 153 | 38:d4:65:ef:db:ba:62:44:8d:88:18:93:72:a7:5c:14:d6:ed: 154 | 0e:a2:25:e8:45:d1:0a:3b:2c:1d:21:94:be:1e:3c:e2:be:6c: 155 | e3:c3:26:41:5f:f0:6b:5b 156 | -----BEGIN CERTIFICATE----- 157 | MIIGXTCCBEWgAwIBAgIJANVnO5yiq+RlMA0GCSqGSIb3DQEBCwUAMIHEMQswCQYD 158 | VQQGEwJERTEWMBQGA1UECAwNRXhhbXBsZSBTdGF0ZTEVMBMGA1UEBwwMRXhhbXBs 159 | ZSBDaXR5MRgwFgYDVQQKDA9FeGFtcGxlIENvbXBhbnkxIjAgBgNVBAsMGUV4YW1w 160 | bGUgT3JnYW5pemF0aW9uIFVuaXQxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUu 161 | Y29tMSkwJwYJKoZIhvcNAQkBFhphZG1pbkByZWdpc3RyeS5leGFtcGxlLmNvbTAe 162 | Fw0xNTEwMjYxMTAyNThaFw0xNjEwMjUxMTAyNThaMIHEMQswCQYDVQQGEwJERTEW 163 | MBQGA1UECAwNRXhhbXBsZSBTdGF0ZTEVMBMGA1UEBwwMRXhhbXBsZSBDaXR5MRgw 164 | FgYDVQQKDA9FeGFtcGxlIENvbXBhbnkxIjAgBgNVBAsMGUV4YW1wbGUgT3JnYW5p 165 | emF0aW9uIFVuaXQxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMSkwJwYJ 166 | KoZIhvcNAQkBFhphZG1pbkByZWdpc3RyeS5leGFtcGxlLmNvbTCCAiIwDQYJKoZI 167 | hvcNAQEBBQADggIPADCCAgoCggIBALOQJJZn3laq47V9J100Tc5gvc+baJ6v5olt 168 | lXSePsYnj7Y0UrqLngLcpnyphGtA4a1bwBn0jT2Bdi3p8S/UIH1QFW3Lts2T6/fS 169 | nJmQG7aZ2K2let+SL6uOuASpzDR/0CFqRomg1StG+EFK7irXVwShM8g//aQQgRtb 170 | W5HJDgyRDur+Ni7zx74BL/T8sKxXO9KTqAytI4EHce86fm+kUsPcun7bmTzF4GaI 171 | jdL2KWylrJy6p90toIutVLL/oMYmkBUM+S/42YAnWlIIjuuEXST+rQXpwm7i8gPO 172 | /C03fs/F7G1F0QXtlxH5a4lm3cxM/bcYcb71x6zhaqVqeKtmFQ5lawhHiwYxmau7 173 | cFCOL6nWmoY5yHnvtmTWACuNecLFxm8CW1BWZE5+9HRjT4BtslUTTpWTHmYbKJxs 174 | axxiY/uaiu0IyOBcBPPdu8DF0lQjuL2qlTBi/ydoQbtovlv4ae8+b4H7CKT3+weC 175 | yVMJ065IAkfb72Cx175twdEt7FAnsimeQ7TmKruZIxtLJ4nEuGQwM6Q7tKH7ZXv/ 176 | UDIOaOre4l+xEeM86bJwqn9ufAENAPn5AmX8hAOqeGYWBK4xugK/PIz2KwvspeL5 177 | 65rOMcwXPkllOXeUaGDYVl5hTVuvEh34uHulMguZxLrL07Qsk5e5/JaF2CcM0pyB 178 | ToVw8KBpAgMBAAGjUDBOMB0GA1UdDgQWBBQcG/wMOTZydkgGsJAm9+PkXRw9FDAf 179 | BgNVHSMEGDAWgBQcG/wMOTZydkgGsJAm9+PkXRw9FDAMBgNVHRMEBTADAQH/MA0G 180 | CSqGSIb3DQEBCwUAA4ICAQCO0hgHsfnxTWBFmOClZI53TT39MT8UKr01yfWTqABj 181 | BVRBRGz+8KvoBLizWOJv3GNYkmO7aswtg3EAF4eR1SSIEY5H0GXpFsH+kuKJbVbw 182 | aTM0w+IfVwBvWDxhL6S/dJNf9HIuWWEZWAAMEwykrSqBtXhP0u09TICoZWZmlZ9a 183 | n6mFBSxL5ct05qNMPytPz/lTsqARsFXUelUwANipMJXxBlgAA5bFzNFOsfhXh3nQ 184 | sc67lSdaltH7SxVeYDerHUFLwvcTKsC7D7i5HxYogHaWH3zatNie7S/ngOdjvE3k 185 | KiA8xMw0isyPxQrEypDmMq+2vSp0hs5yPPABaRVXQRFOVdEmg5t89K1nu69KQzdP 186 | lJOSAPIIuGUYStsPBiq34k0tsGKcRUqdjbMl0JnH7SHgM0vcPhV3eVSuDDEbHdaP 187 | fB4PcGyWbz36YNulPqk6vewu0UmP7NIsBeZVjVVXuKazfIqoobURUCHbffnLJNvo 188 | IAPryqxfFHmt5v8e1B41bA8VtLjCq0Ar5iWkFBsC5xYnqDpvX3mWEbNKd238zU3Q 189 | Fn/DC5761gxNvZLdQ1R/tygnWxQmctJVZmwc4KweEUHSi4wOxpfYssFeBY9mVdXQ 190 | sDjeFqQ41GXv27piRI2IGJNyp1wU1u0OoiXoRdEKOywdIZS+HjzivmzjwyZBX/Br 191 | Ww== 192 | -----END CERTIFICATE----- 193 | 194 | ``` 195 | -------------------------------------------------------------------------------- /certs/auth.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGUTCCBDmgAwIBAgIJAIg5BM++T0GHMA0GCSqGSIb3DQEBCwUAMIG+MQswCQYD 3 | VQQGEwJERTEWMBQGA1UECAwNRXhhbXBsZSBTdGF0ZTEVMBMGA1UEBwwMRXhhbXBs 4 | ZSBDaXR5MRgwFgYDVQQKDA9FeGFtcGxlIENvbXBhbnkxJDAiBgNVBAsMG0V4YW1w 5 | bGUgT3JnYW5pemF0aW9uYWwgVW5pdDEZMBcGA1UEAwwQYXV0aC5leGFtcGxlLmNv 6 | bTElMCMGCSqGSIb3DQEJARYWYWRtaW5AYXV0aC5leGFtcGxlLmNvbTAeFw0xNTEw 7 | MjYxMTAzNDhaFw0xNjEwMjUxMTAzNDhaMIG+MQswCQYDVQQGEwJERTEWMBQGA1UE 8 | CAwNRXhhbXBsZSBTdGF0ZTEVMBMGA1UEBwwMRXhhbXBsZSBDaXR5MRgwFgYDVQQK 9 | DA9FeGFtcGxlIENvbXBhbnkxJDAiBgNVBAsMG0V4YW1wbGUgT3JnYW5pemF0aW9u 10 | YWwgVW5pdDEZMBcGA1UEAwwQYXV0aC5leGFtcGxlLmNvbTElMCMGCSqGSIb3DQEJ 11 | ARYWYWRtaW5AYXV0aC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP 12 | ADCCAgoCggIBANv6wuZ8U9iW8/+RFZOwNC5mrjWdQcAGHHTebrOj0PZDfyDSbOQ6 13 | N+/B06dKgkJe70hDXrKqQV2ABnopJjFumqJAcczVfOEcT7dQJYcRav5OGxPl6c5m 14 | 5KyBMoyFfkclrSrt553ZqbJ90rzbdkXSWobSwZ7y2zORtS91lArRwf4K4ZJWjLC0 15 | 1WUwcpXOeuez+vymhwi4c3d0RT48HLZhdy3t+S3ANE3B0jqwMsWvkfUp3uO8kOHo 16 | ruc1XWdChxj+LfsrNsoQk11iy2OBMmk55usFQbikBRvuNvvWCSmyh5SllOEyM017 17 | E+qqkdEE/bo68EvqLurgzo0BnsW9YaQWblr8Qg38V6pR5ny2WJdW+rI/0cqmSP1r 18 | uOLd0JvrJIUhV1CV1EpJotlgpmxSNMWuxT8T1aWkd4LSt6VHYxySV76CcQ5BkuQ0 19 | JFg3ynfT+M39hniXmA+XTqAb9fg13aBtnJ7wBb5+PzxxDnsGdVtefbVQdIyo/W5V 20 | EK7XRRk3cfrH+0TNI73r4eRN+n4rYwQXiEiT86KIull+XrDVaW4noC6hxDZQuzay 21 | 42CcVnpDdnU1FPby6+GgKBzKrXrvq6jXtuOOMEOToXpjbsE2kyGiGPofcksRhEQv 22 | bwlV8mpBB8zoHWekSMOc59KsUtk9tz7Ud6c3B+mjOEozx/7HJhYIfH4HAgMBAAGj 23 | UDBOMB0GA1UdDgQWBBTbQYvhJfcSfEl2FC+JweoZs5KtiTAfBgNVHSMEGDAWgBTb 24 | QYvhJfcSfEl2FC+JweoZs5KtiTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA 25 | A4ICAQC6IOLZW7rnHt1vgyUsxVcNrJZvQmWyctOyMfMYGsB5OC/LUtwOJWHc1B9v 26 | RCwdnsZi1/TGDQrgfnE5TgROb4ysbOtPNtk9VeDS1OoJuunK8WZl2xgjyscs24Id 27 | jJOrgMHvNvAtEIfmcjnBuqInpysh+fP3eJgcO/61iVU0bxilkeN2zRhnWGr9mIi4 28 | IOyOh3q5tmF/6nHncgrkg1qlozzXIEcJw5X/IKcOJWJlDwWse4lXj3fjK8SvPxz6 29 | JNuLgoVtcT75ZbjHzRrY3n6m2jj+LFuclDs1tLRImMvGrtNleW5ZwUgnMK8367hH 30 | r7GpnVAnnSuKQz7n7efHnHXNet0fakT/4Ie9IbLnvREefBeYNA+P/ugi5MWKIJuR 31 | ALQASAcq/wiMnZ0aWUj2qN5KLM0u+9tRe+GPHF9+ii9McIo+kcPH0opZCLUIx8uw 32 | MwNoaA11xu21+kLgyvMGk2InDgazjiyDSuNbGx9mUH0cGttl+4VtmmMQMkZ0uhf9 33 | fKQb9Fyen+yXPRdrtW+atfnIHa8IM7pm36yQ926JM4cEroqYplXSkOfx9mjEzKWv 34 | YlfEbz3AHB/QG0Kq5lMSOw7fPgNS2iwnwKPwDh0qvyQTIfA/pPQ6qPmr5OOO1+PT 35 | QrWHAjG3qbI3vgzDab32kwevjChelqmfoQyqT0wMypMYmD2L6Q== 36 | -----END CERTIFICATE----- 37 | -------------------------------------------------------------------------------- /certs/auth.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | my7FsXDuRNUL8epD5iO7hhddN53Yig== 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /certs/registry.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGXTCCBEWgAwIBAgIJANVnO5yiq+RlMA0GCSqGSIb3DQEBCwUAMIHEMQswCQYD 3 | VQQGEwJERTEWMBQGA1UECAwNRXhhbXBsZSBTdGF0ZTEVMBMGA1UEBwwMRXhhbXBs 4 | ZSBDaXR5MRgwFgYDVQQKDA9FeGFtcGxlIENvbXBhbnkxIjAgBgNVBAsMGUV4YW1w 5 | bGUgT3JnYW5pemF0aW9uIFVuaXQxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUu 6 | Y29tMSkwJwYJKoZIhvcNAQkBFhphZG1pbkByZWdpc3RyeS5leGFtcGxlLmNvbTAe 7 | Fw0xNTEwMjYxMTAyNThaFw0xNjEwMjUxMTAyNThaMIHEMQswCQYDVQQGEwJERTEW 8 | MBQGA1UECAwNRXhhbXBsZSBTdGF0ZTEVMBMGA1UEBwwMRXhhbXBsZSBDaXR5MRgw 9 | FgYDVQQKDA9FeGFtcGxlIENvbXBhbnkxIjAgBgNVBAsMGUV4YW1wbGUgT3JnYW5p 10 | emF0aW9uIFVuaXQxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMSkwJwYJ 11 | KoZIhvcNAQkBFhphZG1pbkByZWdpc3RyeS5leGFtcGxlLmNvbTCCAiIwDQYJKoZI 12 | hvcNAQEBBQADggIPADCCAgoCggIBALOQJJZn3laq47V9J100Tc5gvc+baJ6v5olt 13 | lXSePsYnj7Y0UrqLngLcpnyphGtA4a1bwBn0jT2Bdi3p8S/UIH1QFW3Lts2T6/fS 14 | nJmQG7aZ2K2let+SL6uOuASpzDR/0CFqRomg1StG+EFK7irXVwShM8g//aQQgRtb 15 | W5HJDgyRDur+Ni7zx74BL/T8sKxXO9KTqAytI4EHce86fm+kUsPcun7bmTzF4GaI 16 | jdL2KWylrJy6p90toIutVLL/oMYmkBUM+S/42YAnWlIIjuuEXST+rQXpwm7i8gPO 17 | /C03fs/F7G1F0QXtlxH5a4lm3cxM/bcYcb71x6zhaqVqeKtmFQ5lawhHiwYxmau7 18 | cFCOL6nWmoY5yHnvtmTWACuNecLFxm8CW1BWZE5+9HRjT4BtslUTTpWTHmYbKJxs 19 | axxiY/uaiu0IyOBcBPPdu8DF0lQjuL2qlTBi/ydoQbtovlv4ae8+b4H7CKT3+weC 20 | yVMJ065IAkfb72Cx175twdEt7FAnsimeQ7TmKruZIxtLJ4nEuGQwM6Q7tKH7ZXv/ 21 | UDIOaOre4l+xEeM86bJwqn9ufAENAPn5AmX8hAOqeGYWBK4xugK/PIz2KwvspeL5 22 | 65rOMcwXPkllOXeUaGDYVl5hTVuvEh34uHulMguZxLrL07Qsk5e5/JaF2CcM0pyB 23 | ToVw8KBpAgMBAAGjUDBOMB0GA1UdDgQWBBQcG/wMOTZydkgGsJAm9+PkXRw9FDAf 24 | BgNVHSMEGDAWgBQcG/wMOTZydkgGsJAm9+PkXRw9FDAMBgNVHRMEBTADAQH/MA0G 25 | CSqGSIb3DQEBCwUAA4ICAQCO0hgHsfnxTWBFmOClZI53TT39MT8UKr01yfWTqABj 26 | BVRBRGz+8KvoBLizWOJv3GNYkmO7aswtg3EAF4eR1SSIEY5H0GXpFsH+kuKJbVbw 27 | aTM0w+IfVwBvWDxhL6S/dJNf9HIuWWEZWAAMEwykrSqBtXhP0u09TICoZWZmlZ9a 28 | n6mFBSxL5ct05qNMPytPz/lTsqARsFXUelUwANipMJXxBlgAA5bFzNFOsfhXh3nQ 29 | sc67lSdaltH7SxVeYDerHUFLwvcTKsC7D7i5HxYogHaWH3zatNie7S/ngOdjvE3k 30 | KiA8xMw0isyPxQrEypDmMq+2vSp0hs5yPPABaRVXQRFOVdEmg5t89K1nu69KQzdP 31 | lJOSAPIIuGUYStsPBiq34k0tsGKcRUqdjbMl0JnH7SHgM0vcPhV3eVSuDDEbHdaP 32 | fB4PcGyWbz36YNulPqk6vewu0UmP7NIsBeZVjVVXuKazfIqoobURUCHbffnLJNvo 33 | IAPryqxfFHmt5v8e1B41bA8VtLjCq0Ar5iWkFBsC5xYnqDpvX3mWEbNKd238zU3Q 34 | Fn/DC5761gxNvZLdQ1R/tygnWxQmctJVZmwc4KweEUHSi4wOxpfYssFeBY9mVdXQ 35 | sDjeFqQ41GXv27piRI2IGJNyp1wU1u0OoiXoRdEKOywdIZS+HjzivmzjwyZBX/Br 36 | Ww== 37 | -----END CERTIFICATE----- 38 | -------------------------------------------------------------------------------- /certs/registry.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | GDJ0k/7Jc0+g7M8Gof7SKU2ItNBjxxQ= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | registry: 2 | image: registry:2 3 | restart: always 4 | ports: 5 | - "5000:5000" 6 | volumes: 7 | - "./certs:/certs:ro" 8 | - "./registry/conf:/etc/docker/registry:ro" 9 | - "./registry/storage:/var/lib/registry:rw" 10 | 11 | auth: 12 | image: cesanta/docker_auth 13 | entrypoint: /start.sh 14 | ports: 15 | - "5001:5001" 16 | links: 17 | - ldap:ldap 18 | volumes: 19 | - "./auth/start.sh:/start.sh:ro" 20 | - "./auth/config:/config:ro" 21 | - "./auth/logs:/logs:rw" 22 | - "./certs:/certs:ro" 23 | 24 | ldap: 25 | build: ./ldap 26 | expose: 27 | - "389" 28 | -------------------------------------------------------------------------------- /docs/setup.graphml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Client 25 | Computer 26 | (Talks HTTPs to registry 27 | and the auth server) 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Docker registry 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | JSON Web Token (JWT) 65 | Auth Server 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | LDAP Server 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | Docker Daemon 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | Docker Client 123 | 124 | docker push your.registry.com/anyuser/busybox 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | docker-compose.yml 144 | configures these containers 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 1 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 2 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 3 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 4 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 5 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 6 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 7 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 8 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | -------------------------------------------------------------------------------- /docs/setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwk/docker-registry-setup/101aa6e8cba1c58174cceee549383efcdfb0fb15/docs/setup.png -------------------------------------------------------------------------------- /ldap/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie 2 | MAINTAINER "Konrad Kleine" 3 | 4 | ############################################################ 5 | # Speedup DPKG and don't use cache for packages 6 | ############################################################ 7 | 8 | # Taken from here: https://gist.github.com/kwk/55bb5b6a4b7457bef38d 9 | # 10 | # this forces dpkg not to call sync() after package extraction and speeds up 11 | # install 12 | RUN echo "force-unsafe-io" > /etc/dpkg/dpkg.cfg.d/02apt-speedup 13 | # # we don't need and apt cache in a container 14 | RUN echo "Acquire::http {No-Cache=True;};" > /etc/apt/apt.conf.d/no-cache 15 | 16 | ############################################################ 17 | # Install slapd, LDAP utils, and supervisor 18 | ############################################################ 19 | 20 | RUN export LC_ALL=C \ 21 | && export DEBIAN_FRONTEND=noninteractive \ 22 | && apt-get -y update \ 23 | && apt-get -y install \ 24 | slapd \ 25 | ldap-utils \ 26 | supervisor \ 27 | netcat-openbsd \ 28 | --no-install-recommends \ 29 | && apt-get -y autoremove \ 30 | && apt-get -y clean \ 31 | && rm -rf /var/lib/apt/lists/* 32 | 33 | # LDAP configuration 34 | ENV LDAP_ROOTPASS password 35 | ENV LDAP_ORGANISATION My Example Organization 36 | ENV LDAP_DOMAIN example.com 37 | 38 | ADD ./setup-ldap-schema.ldif /setup-ldap-schema.ldif 39 | ADD ./setup-ldap-schema.sh /setup-ldap-schema.sh 40 | ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf 41 | ADD slapd.sh /slapd.sh 42 | 43 | # Supervisor manager slapd and the schema setup 44 | CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] 45 | 46 | EXPOSE 389 47 | -------------------------------------------------------------------------------- /ldap/setup-ldap-schema.ldif: -------------------------------------------------------------------------------- 1 | ## # The Organization 2 | ## dn: dc=example,dc=com 3 | ## objectClass: dcObject 4 | ## objectClass: organization 5 | ## o: Example dc: example 6 | 7 | # The organizational unit philosophs 8 | dn: ou=philosophs,dc=example,dc=com 9 | objectClass: organizationalUnit 10 | ou: philosophs 11 | 12 | # The organizational unit musicians 13 | dn: ou=musicians,dc=example,dc=com 14 | objectClass: organizationalUnit 15 | ou: musicians 16 | 17 | # The organizational unit it 18 | dn: ou=it,dc=example,dc=com 19 | objectClass: organizationalUnit 20 | ou: it 21 | 22 | # User account Immanuel Kant 23 | dn: uid=kant,ou=philosophs,dc=example,dc=com 24 | cn: Immanuel Kant 25 | givenName: Immanuel 26 | sn: Kant 27 | uid: kant 28 | uidNumber: 10001 29 | gidNumber: 10001 30 | homeDirectory: /home/kant 31 | mail: kant@example.com 32 | objectClass: top 33 | objectClass: posixAccount 34 | objectClass: shadowAccount 35 | objectClass: inetOrgPerson 36 | objectClass: organizationalPerson 37 | objectClass: person 38 | loginShell: /bin/bash 39 | userPassword: {CRYPT}* 40 | 41 | # User account Arthur Schopenhauer 42 | dn: uid=schopenhauer,ou=philosophs,dc=example,dc=com 43 | cn: Arthur Schopenhauer 44 | givenName: Arthur 45 | sn: Schopenhauer 46 | uid: schopenhauer 47 | uidNumber: 10002 48 | gidNumber: 10002 49 | homeDirectory: /home/schopenhauer 50 | mail: schopenhauer@example.com 51 | objectClass: top 52 | objectClass: posixAccount 53 | objectClass: shadowAccount 54 | objectClass: inetOrgPerson 55 | objectClass: organizationalPerson 56 | objectClass: person 57 | loginShell: /bin/bash 58 | userPassword: {CRYPT}* 59 | 60 | # User account Wolfgang Amadeus Mozart 61 | dn: uid=mozart,ou=musicians,dc=example,dc=com 62 | cn: Wolfgang Amadeus Mozart 63 | givenName: Wolfgang Amadeus 64 | sn: Mozart 65 | uid: mozart 66 | uidNumber: 10003 67 | gidNumber: 10003 68 | homeDirectory: /home/mozart 69 | mail: mozart@example.com 70 | objectClass: top 71 | objectClass: posixAccount 72 | objectClass: shadowAccount 73 | objectClass: inetOrgPerson 74 | objectClass: organizationalPerson 75 | objectClass: person 76 | loginShell: /bin/bash 77 | userPassword: {CRYPT}* 78 | 79 | # User account Johann Sebastian Bach 80 | dn: uid=bach,ou=musicians,dc=example,dc=com 81 | cn: Johann Sebastian Bach 82 | givenName: Johann Sebastian 83 | sn: Bach 84 | uid: bach 85 | uidNumber: 10004 86 | gidNumber: 10004 87 | homeDirectory: /home/bach 88 | mail: bach@example.com 89 | objectClass: top 90 | objectClass: posixAccount 91 | objectClass: shadowAccount 92 | objectClass: inetOrgPerson 93 | objectClass: organizationalPerson 94 | objectClass: person 95 | loginShell: /bin/bash 96 | userPassword: {CRYPT}* 97 | 98 | # Service account 99 | dn: uid=serviceaccount,ou=it,dc=example,dc=com 100 | cn: Service Account 101 | givenName: Service 102 | sn: Account 103 | uid: serviceaccount 104 | uidNumber: 10005 105 | gidNumber: 10005 106 | homeDirectory: /home/serviceaccount 107 | mail: serviceaccount@example.com 108 | objectClass: top 109 | objectClass: posixAccount 110 | objectClass: shadowAccount 111 | objectClass: inetOrgPerson 112 | objectClass: organizationalPerson 113 | objectClass: person 114 | loginShell: /bin/bash 115 | userPassword: {CRYPT}* 116 | -------------------------------------------------------------------------------- /ldap/setup-ldap-schema.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -exu 4 | 5 | while ! netcat -z localhost 389; do 6 | sleep 1 7 | done 8 | 9 | # Create the schema 10 | ldapadd -c -H ldap://localhost:389 -x -D "cn=admin,dc=example,dc=com" -w password -f /setup-ldap-schema.ldif 11 | 12 | # Set user passwords to "password" 13 | 14 | ldappasswd -H ldap://localhost:389 -x -D "cn=admin,dc=example,dc=com" -w password -s password "uid=kant,ou=philosophs,dc=example,dc=com" 15 | ldappasswd -H ldap://localhost:389 -x -D "cn=admin,dc=example,dc=com" -w password -s password "uid=schopenhauer,ou=philosophs,dc=example,dc=com" 16 | ldappasswd -H ldap://localhost:389 -x -D "cn=admin,dc=example,dc=com" -w password -s password "uid=mozart,ou=musicians,dc=example,dc=com" 17 | ldappasswd -H ldap://localhost:389 -x -D "cn=admin,dc=example,dc=com" -w password -s password "uid=bach,ou=musicians,dc=example,dc=com" 18 | ldappasswd -H ldap://localhost:389 -x -D "cn=admin,dc=example,dc=com" -w password -s password "uid=serviceaccount,ou=it,dc=example,dc=com" 19 | 20 | 21 | -------------------------------------------------------------------------------- /ldap/slapd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | status () { 6 | echo "---> ${@}" >&2 7 | } 8 | 9 | set -x 10 | : LDAP_ROOTPASS=${LDAP_ROOTPASS} 11 | : LDAP_DOMAIN=${LDAP_DOMAIN} 12 | : LDAP_ORGANISATION=${LDAP_ORGANISATION} 13 | 14 | if [ ! -e /var/lib/ldap/docker_bootstrapped ]; then 15 | status "configuring slapd for first run" 16 | 17 | cat <