terraform-module.hcloud-user-data

February 1, 2023 · View on GitHub

Description

The purpose of this module is to provide ready to use user-data file for Hetzner cloud servers with multiple network managers.

All actions taken to create user-data file are based on Hetzner server configuration documentation, Hetzner static ip documentation, cloud-init documentation and my own experience/experiments.

Supported features

  • Generating private networks configuration for instance after initial boot ( only dhcp - no support for static interface configuration ). This module use three different ways of managing networks
    • interfaces.d config file - for images:
      • debian-10
      • debian-11
    • Netplan config file - for images:
      • ubuntu-20.04
      • ubuntu-22.04
    • NetworkManager keyfile script - for images:
      • fedora-36
      • fedora-37
      • centos-stream-8
      • centos-stream-9
      • rocky-8
      • rocky-9
  • Adding additional users with ssh keys and sudo configuration
  • Writing additional entries in /etc/hosts file
  • Writing additional files on instance (ex. cron jobs)
  • Running additional shell commands on initial boot (ex. docker instalation)
  • Adding additional packages to VM
  • Setting instance Timezone
  • Upgrading all packages
  • Rebooting after finishing all cloud-init tasks

Working Features for each image

System imageRouting ConfigurationDNS ip addressesDNS search domains/etc/hosts file writingCreating additional usersWriting additional FilesRunning additional commandsUpgrading packagesRebooting instance
Ubuntu 20.04YesYesYesYesYesYesYesYesYes
Ubuntu 22.04YesYesYesYesYesYesYesYesYes
Debian 10YesYesYesYesYesYesYesYesYes
Debian 11YesYesYesYesYesYesYesYesYes
Fedora 36YesYesYesYesYesYesYesYesYes
Fedora 37YesYesYesYesYesYesYesYesYes
Centos Stream 8YesYesYesYesYesYesYesYesYes
Centos Stream 9YesYesYesYesYesYesYesYesYes
Rocky 8YesYesYesYesYesYesYesYesYes
Rocky 9YesYesYesYesYesYesYesYesYes

Please take a look at Known Issues section to read why some of the features are not working on described images.

Tested vms configuration

I have tested this module on below instances types:

  • CX11
  • CPX11

This module should also work on the rest of standard machines with Local SSD based on avaliable documentation.

This module will not work on:

  • Dedicated instances (CCXxx)

Usage example

Example for Debian/Ubuntu with few packages installation:

module "cloud_config_file" {
  source            = "git::git@github.com:wszychta/terraform-module.hcloud-user-data?ref=tags/2.2.0"
  server_type       = "cpx11"
  server_image      = "ubuntu-20.04"
  additional_users  = [
    {
      username = "local"
      sudo_options = "ALL=(ALL) NOPASSWD:ALL"
      ssh_public_keys = [
        "ssh-rsa ..................."
      ]
    }
  ]
  additional_hosts_entries = [
    {
      ip = "192.168.0.4"
      hostnames = [
        "host1.lab.net",
        "host1"
      ]
    },
    {
      ip = "192.168.0.5"
      hostnames = [
        "host2.lab.net",
        "host2"
      ]
    },
  ]
  private_networks_settings = [
    {
      routes = {
        "192.168.0.1" = [
          "192.168.0.0/24",
          "192.168.1.0/24"
          "0.0.0.0/0" # To enable access to public network via NAT
        ]
      }
      nameservers = {
        addresses = [
          "192.168.0.3"
        ]
        search = [
          "lab.net",
        ]
      }
    }
  ]
  additional_run_commands = [
    "echo 'test command'"
  ]
  additional_run_commands = [
    "htop",
    "telnet",
    "nano"
  ]
}

Known Issues

There are no Known Issues known to me for now - please let me know if you will find any.

Internet Access with only private networks defined

To enable access to the internet from instance without public ip addresses there are several things to do:

  • Prepare NAT instance with public IP address or PFsense/Opnsense which will have rules for NAT-ing
  • Add in Hetzner Cloud Console or via hcloud/terraform tool route 0.0.0.0/0 to previously prepared NAT instance/router
  • Add route 0.0.0.0/0 to one of the interfaces defined in private_networks_settings - take a look at the example above
  • Add one or more DNS servers to nameservers in private_networks_settings (They can be public ones or private) - take a look at the example above

Variables

Variable namevariable typedefault valueRequired variableDescription
server_typestringemptyYesHetzner server type (ex. cpx11)
server_imagestringemptyYesInstance system image
additional_users
list(object({
username = string
sudo_options = string
ssh_public_keys = list(string)
}))
[]NoList of additional users with their options
private_networks_onlyboolfalseNoSet to true when there are no public IP addresses defined for the instance
private_networks_settings
list(object({
network_id = string
ip = string
alias_ips = list(string)
routes = map(list(string))
nameservers = object({
addresses = list(string)
search = list(string)
})
})
[]NoList of configuration for all private networks.
Note: Routes are defined as map(list(string)) where key is a gateway ip address and list contains all network destinations.
Example: "192.168.0.1" = ["192.168.0.0/24","192.168.1.0/24"]
additional_write_files
list(object({
content = string
owner_user = string
owner_group = string
destination = string
permissions = string
}))
[]NoList of additional files to create on first boot.
Note: inside content value please provide plain text content of the file (not the path to the file).
You can use terraform to generate file from template or to read existing file from local machine
additional_hosts_entries
list(object({
ip = string
hostnames = string
}))
[]NoList of entries for /etc/hosts file. There is possibility to define multiple hostnames per single ip address
additional_run_commandslist(string)[]NoList of additional commands to run on boot
additional_packageslist(string)[]NoList of additional pckages to install on first boot
timezonestringEurope/BerlinNoTimezone for the VM
upgrade_all_packagesbooltrueNoSet to false when there is no need to upgrade packages on first boot
reboot_instancebooltrueNoSet to false when there is no need for instance reboot after finishing cloud-init tasks
yq_versionstringv4.6.3NoVersion of yq script used for merging netplan script
yq_binarystringyq_linux_amd64NoBinary of yq script used for merging netplan script

Outputs

Output nameDescription
result_fileResult cloud-config file which will be used by instance (depending on provided server_image variable)
result_hosts_fileResult host entries file which will be injected into /etc/hosts file
packages_install_scriptResult packages install script if there are no public network addresses defined for this instance
result_interfacesd_file_mapResult cloud-config for interfaces.d compatible instance
interfaced_network_config_fileResult interfaces.d network file
interfaced_nameservers_fileResult resolvconf file for interfaces.d compatible instance
result_netplan_cloud_config_file_mapResult cloud-config for Netplan compatible instance
netplan_network_fileResult netplan network file which will be merged to main netplan file
netplan_network_merge_scriptResult netplan merge script file
result_ifcfg_cloud_config_mapResult cloud-config for ifcfg network compatible instance
ifcfg_network_config_files_mapResult ifcfg network config files map
ifcfg_network_routes_files_mapResult ifcfg network routes files map
result_keyfile_cloud_config_mapResult cloud-config for Network manager keyfile compatible instance
keyfile_network_config_files_mapResult Network manager keyfiles map

Contributing

Bug Reports/Feature Requests

Please use the issues tab to report any bugs or feature requests.

I can't guarantee that I will work on every bug/feature, because this is my side project, but I will try to keep an eye on any created issue.

So if somebody will discover any error please look into Developing section

Supporting development

If you like this module and you haven't started working in Hetzner Cloud you can use my PERSONAL REFERRAL LINK to start working with Hetzner cloud. You will get 20 Euro on start and after spending additional 10 Euro I will get the same amount of money.

Developing

If you have and idea how to improve this module please:

  1. Fork this module from master branch
  2. Work on your changes inside your fork
  3. Create Pull Request on this respository.
  4. In my spare time I will look at proposed changes

Copyright © 2023 Wojciech Szychta

License

GNU GENERAL PUBLIC LICENSE Version 3