I continuously ask myself, what else in the processes I participate in can be automated? Repeated click-click-click in the interface brings with it a lot of errors, and if the company is actively growing — then all you will do over time — is click in the interface, stop doing it, and let’s automate.
To build a reusable infrastructure, we use the automation of repetitive processes. More often, it will be Terraform. It is difficult to deny the convenience and popularity of this approach, especially when there are already many ready-made and well-supported providers by a large community.
Imagine that our company is growing, new developers and support come to us, and everyone needs to create an account/email in google workspace and attach it to OpenVPN Cloud to access internal resources.
In the most classic version, when a new employee
Also, people are leaving us, and we must not forget to deny access to systems. Here it would be best if you acted strictly in the reverse order of the scheme (scheme 1).
Remember that we have to Terraform for automation. We will use it to automate the issuance and withdrawal of accesses.
The schemes perfectly describe the procedure, but to understand how Terraform will help us, let’s remember its ability to save and share from the output.
I use app.terraform.io to launch terraform and share it with outputs
terraform {
backend "remote" {
hostname = "app.terraform.io"
organization = "EXAMPLE"
workspaces {
name = "google-workspace"
}
}
}
provider "googleworkspace" {
# Use GOOGLEWORKSPACE_CREDENTIALS env
# More settings: https://registry.terraform.io/providers/hashicorp/googleworkspace/latest/docs
customer_id = "XXXXXXX"
}
resource "googleworkspace_user" "arslanbekov" {
primary_email = "[email protected]"
org_unit_path = "developer"
name {
family_name = "Denis"
given_name = "Arslanbekov"
}
}
output "email" {
value = googleworkspace_user.arslanbekov.primary_email
}
output "name" {
value = googleworkspace_user.arslanbekov.name
}
If the user already exists, import it.
terraform import googleworkspace_user.arslanbekov [email protected]
Next, we will interact with the output containing the email and the name of our new employee. We can switch to the following repository, in which we describe the OpenVPN Cloud users:
terraform {
backend "local" {}
required_providers {
openvpncloud = {
source = "OpenVPN/openvpn-cloud"
version = "0.0.7"
}
}
}
provider "openvpncloud" {
base_url = "https://company-name.api.openvpn.com"
}
data "terraform_remote_state" "google_workspace_email" {
backend = "remote"
config = {
organization = "EXAMPLE"
workspaces = {
name = "google-workspace"
}
}
}
resource "openvpncloud_user" "arslanbekov" {
username = "arslanbekov"
email = data.terraform_remote_state.google_workspace_email.outputs.arslanbekov
first_name = data.terraform_remote_state.google_workspace_email.outputs.name.family_name
last_name = data.terraform_remote_state.google_workspace_email.outputs.name.given_name
role = "USER"
}
Applying this code will create a user in the OpenVPN Cloud and send him an invite via email. The user can log in, set a password, and generate VPN certificates.
We can also fully configure OpenVPN Cloud (create groups and describe routes) through this provider. This is really amazing.
We can very quickly invite him to any other systems (using providers that are in terraform).
For example, SendGrid:
terraform {
required_providers {
sendgrid = {
version = "1.0.0"
source = "anna-money/sendgrid"
}
}
}
provider "sendgrid" {
api_key = "SECRET_API_KEY"
}
data "terraform_remote_state" "google_workspace_email" {
backend = "remote"
config = {
organization = "EXAMPLE"
workspaces = {
name = "google-workspace"
}
}
}
resource "sendgrid_teammate" "arslanbekov" {
email = data.terraform_remote_state.google_workspace_email.outputs.arslanbekov
scopes = [
"alerts.create",
"alerts.read",
"alerts.update",
"alerts.delete",
]
is_admin = false
}
The convenience of this approach is that you have one entry point and one exit point. The single-responsibility principle applies here. If a person works in a company — he is always described by the code in one place.
I’ve shown a simple example: I didn’t use loops on purpose, but I strongly advise you to use them to avoid code duplication.
They are also published here.