Manage your Mikrotik with Terraform

In this article I’m going to show a simple example (specific to homelabers) to manage their networking via TF, why? well because winbox is cool but each change we do you probably create a backup right? well I’m least thats me.
So let’s integrate our changes via TF, at least locally not with the idea of GitOps (for now).
Requirements
RouterOS v7.1beta4 or newer
Another user with
writepermissionsA self signed cert for the
www-sslservice androotThe service www-ssl enabled with a cert
Certificates

In case you are on that version, you don’t need to create the root one since it comes built in.
To create the www-ssl one let’s do the following, first ssh into your router or login via winbox, in the terminal type
/certificate
Inside there let’s do
/certificate> add name=root-cert common-name=root-cert key-usage=key-cert-sign,crl-sign
/certificate> add name=https-cert common-name=https-cert
With that we got our certificates created, now we need to sign them. Let’s do the following
/certificate> sign https-cert
progress: done
/certificate> sign root-cert
progress: done
Now let’s enable the web with ssl
/ip service
set www-ssl certificate=https-cert disabled=no
Terraform
Now it’s time to set up our terraform environment, about the provider we are going to use is this https://registry.terraform.io/providers/terraform-routeros/routeros/latest
Folder structure
In my case I like to build them like this (at least when is one environment)
🌳 terraform/
┣ 📁 config/
┃ ┣ 📄 .gitkeep
┃ ┗ 📄 router.tfvars
┣ 📁 router/
┃ ┣ 📄 provider.tf
┃ ┣ 📄 resources.tf
┃ ┗ 📄 variables.tf
┣ 📄 backend.tf
┣ 📄 resources.tf
┗ 📄 versions.tf
In the resources at root level there is something like this
variable "ROS_HOSTURL" {}
variable "ROS_USERNAME" {}
variable "ROS_PASSWORD" {}
module "router" {
source = "./router"
ROS_HOSTURL = var.ROS_HOSTURL
ROS_USERNAME = var.ROS_USERNAME
ROS_PASSWORD = var.ROS_PASSWORD
}
Since I’m using modules I create the variables that get injected at execution time via environment variables
Before doing any king of action remember to create your tf.vars file
The one used in this example has this structure
ROS_HOSTURL="https://<IP_MIKROTIK>"
ROS_USERNAME="<USER_WE_CREATED_BEFORE_WITH_WRITE_ACCESS>"
ROS_PASSWORD="<USER_PASSWORD>"
Running something like
terraform <action> -var-file=config/router.tfvars --auto-approve;
Inside the router module we would need the provider which it’s something like this
terraform {
required_providers {
routeros = {
source = "terraform-routeros/routeros"
}
}
}
provider "routeros" {
hosturl = var.ROS_HOSTURL
username = var.ROS_USERNAME
password = var.ROS_PASSWORD
insecure = true # this is needed because routeros is using self-signed certificates
}
In my case in resources Im just creating DNS so it’s quite simple
locals {
ros_subdomains = [
"...",
"...",
"...",
]
}
resource "routeros_dns_record" "subdomains" {
for_each = toset(local.ros_subdomains)
name = "${each.key}.${var.ROS_BASE_DOMAIN}"
cname = var.ROS_BASE_DOMAIN
type = "CNAME"
comment = var.ROS_COMMENT_DEFAULT
}
And for the variables I’m using are this
variable "ROS_HOSTURL" {
description = "RouterOS host URL"
type = string
default = "http://..."
}
variable "ROS_USERNAME" {
description = "RouterOS username"
type = string
default = ""
sensitive = true
}
variable "ROS_PASSWORD" {
description = "RouterOS password"
type = string
default = ""
sensitive = true
}
variable "ROS_BASE_DOMAIN" {
description = "Base domain for DNS records"
type = string
default = "internal.jonathan.com.ar"
}
variable "ROS_COMMENT_DEFAULT" {
description = "Default comment for RouterOS resources"
type = string
default = "Managed by Terraform"
}
I’ll like to add a comment on each resource managed via TF so I’ll remember later to not modify them manually.
Now we could init the project

Now I'm going to add a new DNS just to update my state and run a terraform plan

Now if I run terraform apply this would create the entry in my router.

We can check it out

And that’s it!
We got our terraform working with RouterOS :)
Destruction
In case you want to destroy everything you can just run terraform destroy




