In this blog, we will go through an example of how you can use the Cloudsmith Terraform Provider to provision resources in Cloudsmith, such as repositories and entitlement tokens.
What is Terraform?
HashiCorp Terraform is an awesome Continuous Configuration Automation tool. It is used to provision, update and manage infrastructure resources such as Cloud instances, containers, physical machines and more.
It is a firm favourite among developers, due to its brilliant community and mix of power and simplicity. At Cloudsmith, we use Terraform to provision and manage our environments (following a rather disastrous outing with an alternative tool), so we are big fans ourselves.
The Terraform Provider
Terraform uses providers to interact with different APIs and expose any required resources. In the case of Cloudsmith, the Cloudsmith Provider allows Terraform to access the Cloudsmith API and manage two resources – Repositories and Entitlement Tokens.
So how do we get started?
Let’s take a walk through setting up Terraform to use the Cloudsmith Provider and create some resources.
The first thing that we need to do is to add the following to the "required_providers" in our example Terraform module:
required_providers {
cloudsmith = {
source = "cloudsmith-io/cloudsmith"
version = "0.0.5"
}
}
This tells Terraform to download and install the Cloudsmith Provider, and which version of the provider to use.
Next, we need to add our Cloudsmith API Key, for use by the Provider:
provider "cloudsmith" {
api_key = "API-KEY"
}
Of course, you should never add credentials or secrets in plain text like this in a Terraform module. You should add them as environment variables, or better yet – use a proper secrets management tool like HashiCorp Vault. Also, Terraform Cloud also allows you to store these credentials securely for free.
But in the interests of simplicity, and to keep this example brief, we will just add our API Key here for now.
We now just need to run “terraform init” to install the provider automatically.
Then we add our namespace data source. The namespace data source is used to identify the Cloudsmith account that the resources we want will be created under:
data "cloudsmith_namespace" "demo_account" {
slug = "demo"
}
The “slug” is the only required argument. It is the user-facing identifier for the Cloudsmith account, which appears in URIs.
And now we get to creating our resources. The first resource we will create is a repository:
resource "cloudsmith_repository" "terraform_example" {
name = "Example Repository"
namespace = "${data.cloudsmith_namespace.demo_account.slug_perm}”
slug = "terraform_example”
}
The required arguments here are:
- name - A name for the repository
- namespace - The namespace is determined from our namespace data source that we added previously.
- slug - A user-facing identifier for the repository, which appears in URI’s
The second resource that we will create is an entitlement token. Entitlement tokens provide read only access to a repository, and we can add restrictions to them to control what package they are allowed to access within the repository, and for how long:
resource "cloudsmith_entitlement" "my_entitlement" {
name = "Entitlement Token 1"
namespace = "${cloudsmith_repository.terraform_example.namespace}"
repository = "${cloudsmith_repository.terraform_example.slug_perm}”
limit_num_downloads = "10"
limit_package_query = "tag:basic"
}
The required arguments here are:
- name - A name for the token
- namespace - The namespace that this token will belong to, which will be determined from the namespace that the repository we create belongs to.
- repository - The repository that this token will be created for, which will be determined from our repository resource.
We have also added two optional arguments to this token, and they are two token restrictions.
The first restriction sets a maximum number of downloads that this token can be used for, and the second restriction sets specific packages, tagged “basic”, that this token is allowed to access. For more detailed information on tokens and restrictions, please see our token documentation.
And that’s it. That’s all we need to add to create a repository and an associated entitlement token with restrictions.
Our complete terraform module now looks like this:
terraform {
required_providers {
cloudsmith = {
source = "cloudsmith-io/cloudsmith"
version = "0.0.5"
}
}
}
provider "cloudsmith" {
api_key = "e783bd53725f3590a2a9e8aab15720026186196a"
}
data "cloudsmith_namespace" "demo_account" {
slug = "demo"
}
resource "cloudsmith_repository" "terraform_example" {
name = "Terraform Example"
namespace = "${data.cloudsmith_namespace.demo_account.slug_perm}"
slug = "terraform_example"
}
resource "cloudsmith_entitlement" "entitlement_1" {
name = "Entitlement Token 1"
namespace = "${cloudsmith_repository.terraform_example.namespace}"
repository = "${cloudsmith_repository.terraform_example.slug_perm}"
limit_num_downloads = "10"
limit_package_query = "tag:basic"
}
If we now just run "terraform plan" we can see the actions that terraform will perform:
The plan confirms that terraform will create two resources, a repository and an entitlement token.
Now, to go ahead and create these resources, we simply run “terraform apply”. We get the same output as we did from the “terraform plan” command, and we are asked to confirm that we want to perform the actions.
When we enter “yes”, Terraform then creates the resources that we have specified:
If we now log into Cloudsmith and check our repositories, we can see our new “terraform_example” repository:
And if we check the entitlement tokens within the repository, we can see the token that we created via Terraform, complete with token restrictions:
To Sum It Up
Terraform and Cloudsmith is a powerful combination. It allows you to automate the creation of your package repositories and associated access tokens in a controlled, reproducible way. Also, as you have now defined these resources as code, you can version them and treat them as you would any other source code that you have.
You can find the full documentation for the Terraform provider here, and a short tutorial video here.
You’re one step further down the DevOps path, long may it continue.