Search code examples
terraformterraform-provider

Terraform Dynamic Provider Options


I'm using the fortios provider to configure my FortiGate firewalls through Terraform, and the hostname and API access token must be hardcoded directly into the provider, similar to below:

terraform {
  required_providers {
    fortios = {
        source = "fortinetdev/fortios"
    }
  }
}

provider "fortios" {
  hostname = "<host>"
  token    = "<api key>"
  insecure = true
}

This obviously isn't great given that I'm backing off my terraform to a git repo, and therefore also storing my authentication credentials. I understand how Terraform works in this sense and that I can't use variables given that it analyses provider configuration before it processes the Terraform code itself, but I'm wondering if I have any options here?

Can it be passed dynamically from an environment variable or something similar? I've seen similar issues that have been resolved with modules and aliases, but this doesn't feel 100% applicable to my situation.


Solution

  • For any information related to who or what is running Terraform the typical approach is to set that using environment variables or some other similar external location, rather than within your Terraform configuration.

    For fortinetdev/fortios in particular I think that means setting the FORTIOS_ACCESS_TOKEN environment variable to contain your access token, and then you can omit token from your provider "fortios" block altogether.

    The tradeoff for hostname is a little more subtle, because this describes what Terraform is managing rather than who or what is running Terraform. In many cases it's appropriate to encode what Terraform is managing in the configuration so that everyone working with that configuration is guaranteed to use the same setting, in which case you'd have a provider block which only sets hostname like this:

    provider "fortios" {
      hostname = "my-fortios-service.example.com"
    }
    

    The access token and the assertion that it's okay to skip TLS certificate verification would then both live in the environment variables, since those settings will presumably vary depending on who is running Terraform and where it is running†.

    In some less fortunate situations the addresses of on-premises services are too ephemeral to be encoded directly in configuration like this, in which case you might prefer to declare an input variable for it and provide a value for that variable each time you run Terraform. However, I would consider that a last resort only if you cannot arrange for all of your services to have stable long-term hostnames, because it creates a risk of someone entering the wrong hostname and e.g. applying staging configuration to the production environment, or similar.


    † If you were to run Terraform in automation on a shared production system, for example, I would typically expect to configure that system to explicitly trust the server's certificate and not set the "insecure" setting; I tend to consider settings like this "insecure" to be just conveniences for during development where Terraform is typically running on developer workstations that do not trust the internal server by default, and therefore varies depending on where Terraform is running.