{"id":13515493,"url":"https://github.com/haoliangyu/terrac","last_synced_at":"2025-03-17T00:33:32.246Z","repository":{"id":189049627,"uuid":"570339702","full_name":"haoliangyu/terrac","owner":"haoliangyu","description":"A minimal private module registry for Terraform and OpenTofu","archived":false,"fork":false,"pushed_at":"2024-08-31T05:19:05.000Z","size":2708,"stargazers_count":30,"open_issues_count":5,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-13T16:43:32.882Z","etag":null,"topics":["azure","cli","gcp","module","opentofu","private-registry","s3","terraform"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haoliangyu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-25T00:03:23.000Z","updated_at":"2024-09-16T11:13:52.000Z","dependencies_parsed_at":"2023-12-31T05:22:41.410Z","dependency_job_id":"8a959579-4b7d-4d2d-bd10-9dad2f7640be","html_url":"https://github.com/haoliangyu/terrac","commit_stats":null,"previous_names":["haoliangyu/terrac"],"tags_count":3,"template":false,"template_full_name":"haoliangyu/node-project-starter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haoliangyu%2Fterrac","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haoliangyu%2Fterrac/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haoliangyu%2Fterrac/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haoliangyu%2Fterrac/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haoliangyu","download_url":"https://codeload.github.com/haoliangyu/terrac/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221669507,"owners_count":16860896,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure","cli","gcp","module","opentofu","private-registry","s3","terraform"],"created_at":"2024-08-01T05:01:11.962Z","updated_at":"2024-10-27T11:36:50.616Z","avatar_url":"https://github.com/haoliangyu.png","language":"TypeScript","funding_links":[],"categories":["Tools"],"sub_categories":["Registry"],"readme":"# terrac\n\nA simple CLI tool to quickly setup a minimal private terraform module registry with your cloud storage service.\n\n[![Version](https://img.shields.io/npm/v/terrac.svg)](https://npmjs.org/package/terrac)\n[![License](https://img.shields.io/npm/l/terrac.svg)](https://github.com/haoliangyu/terrac/blob/main/package.json)\n[![Main](https://github.com/haoliangyu/terrac/actions/workflows/main.yaml/badge.svg)](https://github.com/haoliangyu/terrac/actions/workflows/main.yaml)\n\n\u003c!-- toc --\u003e\n\n* [Why](#why)\n* [Design](#design)\n* [Installation](#installation)\n* [Tutorial](#tutorial)\n* [Configuration](#configuration)\n* [Commands](#commands)\n* [Backends](#backends)\n* [Limitations](#limitations)\n* [Roadmap](#roadmap)\n* [Development](#development)\n\n\u003c!-- tocstop --\u003e\n\n## Why\n\n\u003c!-- why --\u003e\n\nSharing terraform module privately is usually necessary when the infrastructure development happens across multiple teams (DevOps vs applications) or multiple repositories (core vs. app infrastructure).\n\nWhile a module can be downloaded from a git URL, it lacks the support to code versionization and storage management. While other paid solutions (like [Terraform Cloud](https://developer.hashicorp.com/terraform/cloud-docs/registry)) or open-source solutions (like [citizen](https://github.com/outsideris/citizen)) exist as a full-feature registry, they are usually very heavy for small teams, in terms of const, features, or maintenance.\n\nThe `terrac` CLI provides a thin layer on your choice of cloud storage service, such as [AWS S3](https://aws.amazon.com/s3/) or [GCP Cloud Storage](https://cloud.google.com/storage/), to publish and share private module code.  It provides features:\n\n* Publish and download with [semver](https://semver.org)\n* Manage storage schema and metadata automatically\n* Fully integrated with your infrastructure\n* Completely serverless (nothing is hosted)\n* Simple commands (npm-style)\n* Free and flexible\n\nIt is suitable to use as a private terraform registry in small teams (while limitations apply).\n\n\u003c!-- whystop --\u003e\n\n## Design\n\n\u003c!-- design --\u003e\n\nThe desing of `terrac` consists of three components:\n\n* **Configuration**: a JSON file to provide configurations on the module and the cloud storage service\n* **Commands**: a set of commands to provide user interface and interaction\n* **Backends**: a set of standard abstractions for different cloud storage services. All backends expose the same interface to the commands and encapuslate the details of interaction with the remote API.\n\n```mermaid\ngraph TD;\n    Configuration--\u003eCommand:publish;\n    Command:publish--\u003eBackend:s3;\n    Command:publish--\u003eBackend:gcp;\n    Command:publish--\u003eBackend:azure;\n    Backend:gcp--\u003eGCP;\n    Backend:azure--\u003eAzure;\n    Backend:s3--\u003eAWS;\n```\n\n\u003c!-- designstop --\u003e\n\n## Installation\n\n\u003c!-- installation --\u003e\n\n### npm\n\nAs a node.js application, terrac can be installed with [npm](https://www.npmjs.com) or other compatible package managers, such as [yarn](https://yarnpkg.com) or [pnpm](https://pnpm.io).\n\n```bash\nnpm install -g terrac\n```\n\n### manual\n\nBinaries for diefferent platforms are provided as attachment at each [GitHub release](https://github.com/haoliangyu/terrac/releases):\n\n* `terrac-linux` for Linux\n* `terrac-macos` for MacOS\n* `terrac-win.exe` for Windowns\n\nYou can simply download a binary and put it in a directoy included in the `PATH` environment variable. Note that administrator permission may be required for the action.\n\n### bash\n\nThe following script automates the manual installation with a bash script in Linux and MacOS.\n\n``` bash\ncurl https://raw.githubusercontent.com/haoliangyu/terrac/main/scripts/install.sh | bash\n```\n\n\u003c!-- tutorial --\u003e\n\n## Tutorial\n\nTo initialize a module directory and publish\n\n``` bash\n# Create terrac configuration\nterrac init\n\n# Pack and publish the module to the remote storage service\nterrac publish\n\n# Get the module source URL to use in terraform\nterrac get module-name\n```\n\n\u003c!-- tutorialstop --\u003e\n\n\u003c!-- installationstop --\u003e\n\n## Configuration\n\n\u003c!-- configuration --\u003e\n\nA `terrac.json` file at the module root directory is used to provide configuration for terrac. It contains two blocks:\n\n* **backend** to provide the cloud storage configuration\n* **module** to provide the module metadata\n\nThe JSON configuration can be populated interactively using the `terrac init` command and this is an example:\n\n```json\n{\n  \"backend\": {\n    \"type\": \"s3\",\n    \"bucket\": \"team-sharing\",\n    \"region\": \"us-east-1\"\n  },\n  \"module\": {\n    \"name\": \"custom-rds-module\",\n    \"version\": \"1.6.3\"\n  }\n}\n```\n\n### Backend\n\nSee the [Backends](#backends) section for more details.\n\n### Module\n\nThe `module` object describes the meta information for the module to publish:\n\n* **name**: module name\n* **version**: module version number. This could be a sematic version or a custom version name.\n\n\u003c!-- configurationstop --\u003e\n\n## Commands\n\n\u003c!-- commands --\u003e\n\n* [`terrac init`](#terrac-init)\n* [`terrac get`](#terrac-get)\n* [`terrac list`](#terrac-list)\n* [`terrac publish`](#terrac-publish)\n\n### `terrac init`\n\nInitialize terrac configuration in a directory. It will provide an interactive questionnaire for the selected backend and create the `terrac.json` configuration file at the local directory.\n\n```\nUSAGE\n  $ terrac init [--work-directory \u003cvalue\u003e]\n\nFLAGS\n  --work-directory=\u003cvalue\u003e  [default: .] Root directory of the terraform project\n\nDESCRIPTION\n  Initialize terrac configuration in a directory.\n```\n\n_See code: [src/commands/init.ts](https://github.com/haoliangyu/terrac/blob/master/src/commands/init.ts)_\n\n### `terrac get`\n\nGet the module source URL with the given module and version.\n\n```\nUSAGE\n  $ terrac get NAME [VERSION] [--exact] [--work-directory \u003cvalue\u003e]\n\nARGUMENTS\n  NAME     Module name\n  VERSION  Module version. This could be a version name (like latest), a semver, or a semver component.\n           By default, terrac will verify the release with the input version and generate the source URL.\n           If it needs to resolve to an exact version, use the --exact flag.\n\nFLAGS\n  --exact                   Whether to resolve to an exact version if a named version or a semver component is given\n  --work-directory=\u003cvalue\u003e  [default: .] Root directory of the module configuration\n\nDESCRIPTION\n  Get the module source URL of the given module and version.\n\nEXAMPLES\n  $ terrac get my-module\n\n  $ terrac get my-module latest\n\n  $ terrac get my-module 1.3.2\n\n  $ terrac get my-module 1.3\n\n  $ terrac get --exact my-module 1.3\n```\n\nThe command will try to automatically resolve to the desired version. If the version is found at the backend, it will provide the download URL as output\n\n```\nThe release 1.3.2 is found and available at s3::https://s3-us-east-1.amazonaws.com/test-bucket/test-module/1.3.2/module.zip\n```\n\nThe output URL can be used in the module `source` property. For example,\n\n``` terraform\nmodule \"example\" {\n  source = \"s3::https://s3-us-east-1.amazonaws.com/test-bucket/test-module/1.3.2/module.zip\"\n}\n```\n\n_See code: [src/commands/get.ts](https://github.com/haoliangyu/terrac/blob/master/src/commands/get.ts)_\n\n### `terrac list`\n\nList available modules and their versions.\n\n```\nUSAGE\n  $ terrac list [NAME] [--work-directory \u003cvalue\u003e]\n\nARGUMENTS\n  NAME  Module name\n\nFLAGS\n  --work-directory=\u003cvalue\u003e       [default: .] Root directory for the terrac configuration file\n\nDESCRIPTION\n  List available modules and versions.\n\nEXAMPLES\n  $ terrac list\n\n  $ terrac list my-module\n```\n\nIf the module name is provided, it will print a list of available versions for the given module. Otherwise, it will list all published modules in the backend.\n\n_See code: [src/commands/list.ts](https://github.com/haoliangyu/terrac/blob/master/src/commands/list.ts)_\n\n### `terrac publish`\n\nPublish a terraform module using the metadata from the `terrac.json` configuration. If a version name (like `beta`) is specified, it will publish a single release with the version `beta`. If a semver is specified, it will publish multile releaes with each semver component. For example, the version `1.3.2` will create three releases (`1`, `1.3`, `1.3.2`) and each will have it own downloadable source URL.\n\nA `latest` release will be updated at every publication.\n\n```\nUSAGE\n  $ terrac publish [--overwrite] [--work-directory \u003cvalue\u003e]\n\nFLAGS\n  --overwrite               Overwrite a published version with a new package\n  --work-directory=\u003cvalue\u003e  [default: .] Root directory of the module project\n\nDESCRIPTION\n  Publish a terraform module.\n\nEXAMPLES\n  $ terrac publish\n\n  $ terrac publish --overwrite\n```\n\nOnce the publication is successful, it will list all updated releases with the download URLs.\n\n_See code: [src/commands/publish.ts](https://github.com/haoliangyu/terrac/blob/master/src/commands/publish.ts)_\n\n####\n\n\u003c!-- commandsstop --\u003e\n\n## Backends\n\n\u003c!-- backends --\u003e\n\nTerrac supports a variety of storage backends for artifact hosting:\n* Local\n* AWS S3\n* GCP Storage\n* Azure Block Storage\n\nTo set a backend for module publication, update the `backend` block in the `terrac.json` configuration file.\n\n### Local Directory\n\nThe `local` backend type uses a local directory for package storage. It is typically used for local testing.\n\n``` jsonc\n// terrac.json\n{\n  \"backend\": {\n    \"type\": \"local\",\n    // path to the storage directory\n    \"path\": \"./\"\n  }\n}\n```\n\n### AWS S3\n\nThe `s3` backend type uses an [AWS S3](https://aws.amazon.com/s3/) bucket for artifact storage. It utilizes the AWS SDK for JavaScript to communicate with AWS and requires proper authentication setup (see [documentation](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html)).\n\n``` jsonc\n// terrac.json\n{\n  \"backend\": {\n    \"type\": \"s3\",\n    // bucket name\n    \"bucket\": \"module-bucket\",\n    // bucket region\n    \"region\": \"us-east-1\"\n  }\n}\n```\n\n### GCP Cloud Storage\n\nThe `gcp` backend type uses a [GCP Cloud Storage](https://cloud.google.com/storage) bucket for artifact storage. It uses the GCP Node.js SDK to communicate with GCP and requires proper authentication setup (see [documentation](https://cloud.google.com/docs/authentication/provide-credentials-adc)).\n\n``` jsonc\n// terrac.json\n{\n  \"backend\": {\n    \"type\": \"gcp\",\n    // bucket name\n    \"bucket\": \"module-bucket\",\n    // project id\n    \"projectId\": \"my-module-registry\"\n  }\n}\n```\n\n### Azure Blob Storage\n\nThe `azure` backend type uses a [Azure Blog Storage](https://azure.microsoft.com/en-us/products/storage/blobs) container for artifact storage.\n\n``` jsonc\n// terrac.json\n{\n  \"backend\": {\n    \"type\": \"azure\",\n    // Azure storage account name\n    \"account\": \"terrac\",\n    // Azure storage container name\n    \"conatiner\": \"terrac-test\",\n    // [Optional] File name prefix\n    \"fileNamePrefix\": \"name/prefix\"\n  }\n}\n```\n\n\u003c!-- backendsstop --\u003e\n\n## Limitations\n\n\u003c!-- limitations --\u003e\n\nThe purpose of `terrac` is to provide a consistent and simple interface for terraform module hosting with a variety of storage backends. It focuses on the module publication and download. However, it doesn't provide or guarantee some advanced features of modern artifact registry, such as:\n* Authentication\n* High availability\n* High scalability\n* Atomic write\n* Conflict control\n* Permission control\n\nIt may be possible to configure a storage backend for these features but this is out of the scope of this project.\n\n\u003c!-- limitationsstop --\u003e\n\n## Roadmap\n\n\u003c!-- roadmap --\u003e\n\n* Features\n   * [x] Add `overwrite` option to the `publish` command\n   * [x] Add `init` command to interatively initialize a module project\n   * [x] Add schema check to the terrac configuration file\n   * [x] Add support to any custom version name in the `get` and `publish` commands\n   * [x] Add support to using partial semver in the `get` command\n   * [ ] Install with brew\n   * [x] Install with bash script\n   * [x] Install with standalone executable in different OS\n   * [ ] Use backend configuration schema to configure `init` command questionnaire\n\n* Backends\n   * [x] GCP Cloud Storage\n   * [x] Azure Blob Storage\n\n* Maintenance\n  * [ ] Add E2E tests with `terraform` and `OpenTofu`\n  * [ ] Unit tests for `init` command\n  * [ ] Automate release process to cut GitHub release\n\n\u003c!-- roadmapstop --\u003e\n\n## Development\n\n\u003c!-- development --\u003e\n\nIn order to run tests locally, it requires the following packages to be installed:\n* [localstack](https://github.com/localstack/localstack#installation)\n* [awscli-local](https://github.com/localstack/awscli-local)\n\n\u003c!-- developmentstop --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaoliangyu%2Fterrac","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaoliangyu%2Fterrac","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaoliangyu%2Fterrac/lists"}