├── .gitignore ├── LICENSE ├── README.md ├── examples └── main.tf ├── main.py ├── providers └── hashicorp │ └── random.json └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .terraform 3 | .terraform* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Hugo Martins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rekisteri 2 | 3 | `rekisteri` is a private Terraform Registry that serves Terraform's [Provider Registry Protocol](https://www.terraform.io/docs/internals/provider-registry-protocol.html). 4 | 5 | For now, only a local filesystem backend is provided, which means only information from the metadata in those files is available, and there's only 3 endpoints - which comply with Terraform's protocol. 6 | 7 | Check the `providers` folder for examples of structure and hierarchy of the files with metadata. 8 | 9 | ## Requirements 10 | 11 | - Python 3.8.3 12 | - Flask 1.1.2 13 | 14 | ## Running 15 | 16 | ``` 17 | $ FLASK_ENV=development FLASK_APP=main.py flask run 18 | ``` 19 | 20 | ## Backends 21 | 22 | - Filesystem (yes, really!) 23 | 24 | ## Examples 25 | 26 | To start service discovery, we use Terraform's [mechanisms](https://www.terraform.io/docs/internals/remote-service-discovery.html): 27 | 28 | ``` 29 | $ http http://localhost:5000/.well-known/terraform.json 30 | HTTP/1.0 200 OK 31 | Content-Length: 39 32 | Content-Type: application/json 33 | Date: Thu, 31 Dec 2020 09:33:08 GMT 34 | Server: Werkzeug/1.0.1 Python/3.8.3 35 | 36 | { 37 | "providers.v1": "/v1/providers/" 38 | } 39 | ``` 40 | 41 | To list existing versions for a Provider: 42 | 43 | ``` 44 | http http://localhost:5000/v1/providers/hashicorp/random/versions 45 | HTTP/1.0 200 OK 46 | Content-Length: 225 47 | Content-Type: application/json 48 | Date: Thu, 31 Dec 2020 09:38:27 GMT 49 | Server: Werkzeug/1.0.1 Python/3.8.3 50 | 51 | { 52 | "versions": [ 53 | { 54 | "platforms": [ 55 | { 56 | "arch": "amd64", 57 | "os": "linux" 58 | } 59 | ], 60 | "protocols": [ 61 | "4.0", 62 | "5.1" 63 | ], 64 | "version": "2.0.0" 65 | } 66 | ] 67 | } 68 | ``` 69 | 70 | To get information for a specific Provider: 71 | 72 | ``` 73 | http http://localhost:5000/v1/providers/hashicorp/random/2.0.0/download/linux/amd64 74 | HTTP/1.0 200 OK 75 | Content-Length: 2643 76 | Content-Type: application/json 77 | Date: Thu, 31 Dec 2020 09:39:13 GMT 78 | Server: Werkzeug/1.0.1 Python/3.8.3 79 | 80 | { 81 | "arch": "amd64", 82 | "download_url": "https://releases.hashicorp.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_linux_amd64.zip", 83 | "filename": "terraform-provider-random_2.0.0_linux_amd64.zip", 84 | "os": "linux", 85 | "protocols": [ 86 | "4.0", 87 | "5.1" 88 | ], 89 | "shasum": "5f9c7aa76b7c34d722fc9123208e26b22d60440cb47150dd04733b9b94f4541a", 90 | "shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_SHA256SUMS.sig", 91 | "shasums_url": "https://releases.hashicorp.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_SHA256SUMS", 92 | "signing_keys": { 93 | "gpg_public_keys": [ 94 | { 95 | "ascii_armor": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v1\n\nmQENBFMORM0BCADBRyKO1MhCirazOSVwcfTr1xUxjPvfxD3hjUwHtjsOy/bT6p9f\nW2mRPfwnq2JB5As+paL3UGDsSRDnK9KAxQb0NNF4+eVhr/EJ18s3wwXXDMjpIifq\nfIm2WyH3G+aRLTLPIpscUNKDyxFOUbsmgXAmJ46Re1fn8uKxKRHbfa39aeuEYWFA\n3drdL1WoUngvED7f+RnKBK2G6ZEpO+LDovQk19xGjiMTtPJrjMjZJ3QXqPvx5wca\nKSZLr4lMTuoTI/ZXyZy5bD4tShiZz6KcyX27cD70q2iRcEZ0poLKHyEIDAi3TM5k\nSwbbWBFd5RNPOR0qzrb/0p9ksKK48IIfH2FvABEBAAG0K0hhc2hpQ29ycCBTZWN1\ncml0eSA8c2VjdXJpdHlAaGFzaGljb3JwLmNvbT6JATgEEwECACIFAlMORM0CGwMG\nCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFGFLYc0j/xMyWIIAIPhcVqiQ59n\nJc07gjUX0SWBJAxEG1lKxfzS4Xp+57h2xxTpdotGQ1fZwsihaIqow337YHQI3q0i\nSqV534Ms+j/tU7X8sq11xFJIeEVG8PASRCwmryUwghFKPlHETQ8jJ+Y8+1asRydi\npsP3B/5Mjhqv/uOK+Vy3zAyIpyDOMtIpOVfjSpCplVRdtSTFWBu9Em7j5I2HMn1w\nsJZnJgXKpybpibGiiTtmnFLOwibmprSu04rsnP4ncdC2XRD4wIjoyA+4PKgX3sCO\nklEzKryWYBmLkJOMDdo52LttP3279s7XrkLEE7ia0fXa2c12EQ0f0DQ1tGUvyVEW\nWmJVccm5bq25AQ0EUw5EzQEIANaPUY04/g7AmYkOMjaCZ6iTp9hB5Rsj/4ee/ln9\nwArzRO9+3eejLWh53FoN1rO+su7tiXJA5YAzVy6tuolrqjM8DBztPxdLBbEi4V+j\n2tK0dATdBQBHEh3OJApO2UBtcjaZBT31zrG9K55D+CrcgIVEHAKY8Cb4kLBkb5wM\nskn+DrASKU0BNIV1qRsxfiUdQHZfSqtp004nrql1lbFMLFEuiY8FZrkkQ9qduixo\nmTT6f34/oiY+Jam3zCK7RDN/OjuWheIPGj/Qbx9JuNiwgX6yRj7OE1tjUx6d8g9y\n0H1fmLJbb3WZZbuuGFnK6qrE3bGeY8+AWaJAZ37wpWh1p0cAEQEAAYkBHwQYAQIA\nCQUCUw5EzQIbDAAKCRBRhS2HNI/8TJntCAClU7TOO/X053eKF1jqNW4A1qpxctVc\nz8eTcY8Om5O4f6a/rfxfNFKn9Qyja/OG1xWNobETy7MiMXYjaa8uUx5iFy6kMVaP\n0BXJ59NLZjMARGw6lVTYDTIvzqqqwLxgliSDfSnqUhubGwvykANPO+93BBx89MRG\nunNoYGXtPlhNFrAsB1VR8+EyKLv2HQtGCPSFBhrjuzH3gxGibNDDdFQLxxuJWepJ\nEK1UbTS4ms0NgZ2Uknqn1WRU1Ki7rE4sTy68iZtWpKQXZEJa0IGnuI2sSINGcXCJ\noEIgXTMyCILo34Fa/C6VCm2WBgz9zZO8/rHIiQm1J5zqz0DrDwKBUM9C\n=LYpS\n-----END PGP PUBLIC KEY BLOCK-----", 96 | "key_id": "51852D87348FFC4C", 97 | "source": "HashiCorp", 98 | "source_url": "https://www.hashicorp.com/security.html", 99 | "trust_signature": "" 100 | } 101 | ] 102 | } 103 | } 104 | ``` 105 | -------------------------------------------------------------------------------- /examples/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 0.13" 3 | required_providers { 4 | random = { 5 | source = "9af044367099.ngrok.io/hashicorp/random" 6 | version = "~> 0.1" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import json 2 | from flask import Flask, abort 3 | from os import path 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/.well-known/terraform.json', methods=['GET']) 8 | def discovery(): 9 | return {"providers.v1": "/v1/providers/"} 10 | 11 | @app.route('/v1/providers///versions', methods=['GET']) 12 | def versions(namespace, name): 13 | filepath = 'providers/' + namespace + "/" + name + ".json" 14 | 15 | if not path.exists(filepath): 16 | abort(404) 17 | 18 | with open(filepath) as reader: 19 | data = json.load(reader) 20 | 21 | response = { "versions" : [] } 22 | 23 | for elem in data["versions"]: 24 | version = {"version": elem["version"], "protocols": elem["protocols"], "platforms": []} 25 | 26 | for platform in elem["platforms"]: 27 | version["platforms"].append({"os": platform["os"], "arch": platform["arch"]}) 28 | 29 | response["versions"].append(version) 30 | 31 | return response 32 | 33 | @app.route('/v1/providers////download//', methods=['GET']) 34 | def package(namespace, name, version, os, arch): 35 | filepath = 'providers/' + namespace + "/" + name + ".json" 36 | 37 | if not path.exists(filepath): 38 | abort(404) 39 | 40 | with open(filepath) as reader: 41 | data = json.load(reader) 42 | 43 | provider = None 44 | 45 | for elem in data["versions"]: 46 | if elem["version"] == version: 47 | for platform in elem["platforms"]: 48 | if platform["os"] == os and platform["arch"]: 49 | provider = platform 50 | provider["protocols"] = elem["protocols"] 51 | 52 | if provider is None: 53 | abort(404) 54 | 55 | return provider -------------------------------------------------------------------------------- /providers/hashicorp/random.json: -------------------------------------------------------------------------------- 1 | { 2 | "versions": [ 3 | { 4 | "version": "0.1.0", 5 | "protocols": [ 6 | "4.0", 7 | "5.1" 8 | ], 9 | "platforms": [ 10 | { 11 | "os": "linux", 12 | "arch": "amd64", 13 | "filename": "terraform-provider-random_2.0.0_linux_amd64.zip", 14 | "download_url": "https://releases.hashicorp.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_linux_amd64.zip", 15 | "shasums_url": "https://releases.hashicorp.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_SHA256SUMS", 16 | "shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_SHA256SUMS.sig", 17 | "shasum": "5f9c7aa76b7c34d722fc9123208e26b22d60440cb47150dd04733b9b94f4541a", 18 | "signing_keys": { 19 | "gpg_public_keys": [ 20 | { 21 | "key_id": "51852D87348FFC4C", 22 | "ascii_armor": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v1\n\nmQENBFMORM0BCADBRyKO1MhCirazOSVwcfTr1xUxjPvfxD3hjUwHtjsOy/bT6p9f\nW2mRPfwnq2JB5As+paL3UGDsSRDnK9KAxQb0NNF4+eVhr/EJ18s3wwXXDMjpIifq\nfIm2WyH3G+aRLTLPIpscUNKDyxFOUbsmgXAmJ46Re1fn8uKxKRHbfa39aeuEYWFA\n3drdL1WoUngvED7f+RnKBK2G6ZEpO+LDovQk19xGjiMTtPJrjMjZJ3QXqPvx5wca\nKSZLr4lMTuoTI/ZXyZy5bD4tShiZz6KcyX27cD70q2iRcEZ0poLKHyEIDAi3TM5k\nSwbbWBFd5RNPOR0qzrb/0p9ksKK48IIfH2FvABEBAAG0K0hhc2hpQ29ycCBTZWN1\ncml0eSA8c2VjdXJpdHlAaGFzaGljb3JwLmNvbT6JATgEEwECACIFAlMORM0CGwMG\nCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFGFLYc0j/xMyWIIAIPhcVqiQ59n\nJc07gjUX0SWBJAxEG1lKxfzS4Xp+57h2xxTpdotGQ1fZwsihaIqow337YHQI3q0i\nSqV534Ms+j/tU7X8sq11xFJIeEVG8PASRCwmryUwghFKPlHETQ8jJ+Y8+1asRydi\npsP3B/5Mjhqv/uOK+Vy3zAyIpyDOMtIpOVfjSpCplVRdtSTFWBu9Em7j5I2HMn1w\nsJZnJgXKpybpibGiiTtmnFLOwibmprSu04rsnP4ncdC2XRD4wIjoyA+4PKgX3sCO\nklEzKryWYBmLkJOMDdo52LttP3279s7XrkLEE7ia0fXa2c12EQ0f0DQ1tGUvyVEW\nWmJVccm5bq25AQ0EUw5EzQEIANaPUY04/g7AmYkOMjaCZ6iTp9hB5Rsj/4ee/ln9\nwArzRO9+3eejLWh53FoN1rO+su7tiXJA5YAzVy6tuolrqjM8DBztPxdLBbEi4V+j\n2tK0dATdBQBHEh3OJApO2UBtcjaZBT31zrG9K55D+CrcgIVEHAKY8Cb4kLBkb5wM\nskn+DrASKU0BNIV1qRsxfiUdQHZfSqtp004nrql1lbFMLFEuiY8FZrkkQ9qduixo\nmTT6f34/oiY+Jam3zCK7RDN/OjuWheIPGj/Qbx9JuNiwgX6yRj7OE1tjUx6d8g9y\n0H1fmLJbb3WZZbuuGFnK6qrE3bGeY8+AWaJAZ37wpWh1p0cAEQEAAYkBHwQYAQIA\nCQUCUw5EzQIbDAAKCRBRhS2HNI/8TJntCAClU7TOO/X053eKF1jqNW4A1qpxctVc\nz8eTcY8Om5O4f6a/rfxfNFKn9Qyja/OG1xWNobETy7MiMXYjaa8uUx5iFy6kMVaP\n0BXJ59NLZjMARGw6lVTYDTIvzqqqwLxgliSDfSnqUhubGwvykANPO+93BBx89MRG\nunNoYGXtPlhNFrAsB1VR8+EyKLv2HQtGCPSFBhrjuzH3gxGibNDDdFQLxxuJWepJ\nEK1UbTS4ms0NgZ2Uknqn1WRU1Ki7rE4sTy68iZtWpKQXZEJa0IGnuI2sSINGcXCJ\noEIgXTMyCILo34Fa/C6VCm2WBgz9zZO8/rHIiQm1J5zqz0DrDwKBUM9C\n=LYpS\n-----END PGP PUBLIC KEY BLOCK-----", 23 | "trust_signature": "", 24 | "source": "HashiCorp", 25 | "source_url": "https://www.hashicorp.com/security.html" 26 | } 27 | ] 28 | } 29 | } 30 | ] 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==1.1.2 --------------------------------------------------------------------------------