Skip to main content

Command Palette

Search for a command to run...

Manage your Mikrotik with Terraform

Updated
3 min read
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 write permissions

  • A self signed cert for the www-ssl service and root

  • The 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

More from this blog

J

jd-apprentice - blog

29 posts

🧰 devops | 💻 tech | 📚 linux | 💖 anime