Skip to content

Using Terraform to build cloud-config and netplan files which can be used to configure bare metal and virtual instances. It uses a subset of capabilities of cloud-init and has been tested with Ubuntu Bionic, Focal and Groovy. You can use it to configure your Raspberry Pi computers all the same as bootstrap your cloud VMs.

License

Notifications You must be signed in to change notification settings

OmegaSquad82/terraform-template-cloud-init

Repository files navigation

instance configuration generator

This module generates configuration for cloud-init and netplan. I aims as complete as necessary to create meaningful instances for your bare metal or virtual machines with Ubuntu or other operating systems that work with cloud-init. Right now it's optimized to generate working user-data and network-config files for Ubuntu 20.10 Groovy Gorilla on Raspberry Pi 4B. I believe older releases should work out of the box.

References

Modules

Technologies

Requirements

Name Version
terraform >= 0.13

Providers

No providers.

Modules

Name Source Version
network-config ./modules/network-config n/a
static-copy ./modules/static-copy n/a
user-data ./modules/user-data n/a

Resources

No resources.

Inputs

Name Description Type Default Required
apt Module 'apt' for Debian-style package manager's configuration. Proxy is optional. map {} no
byobu_by_default If to activate Byobu.io and on what level. string "user" no
ca_certs Inserted from ca-certs examples https://cloudinit.readthedocs.io/en/latest/topics/examples.html?highlight=cert#configure-an-instances-trusted-ca-certificates
object({
remove-defaults = bool
trusted = list(string)
})
{
"remove-defaults": false,
"trusted": []
}
no
chpasswd Sets the password for users. Be careful on what you configure here!

If you set a definitive user:password (like ubuntu:ubuntu) pair it is recommended
to expire the password on the first login, then change it right away to your secret.

On the other hand if you know in advance that you're going to use an SSH key pair
you might use a RANDOM value here. Please note that this effectively locks you out
of console access so you should have some fallback plan like to boot into a shell.
object({
expire = bool
list = list(string)
})
{
"expire": true,
"list": [
"ubuntu:ubuntu"
]
}
no
config bootcmd: Please state shell commands that shall be executed per boot for 'machine' type, operating 'system', instance 'role'.
runcmd: Please state shell commands that shall be executed on first boot for 'machine' type, operating 'system', instance 'role'.
packages: Please state packages that shall be installed per 'machine' type, operating 'system', instance 'role'.
map(map(map(list(string))))
{
"bootcmd": {
"roles": {
"generic": [
"neofetch --stdout"
]
}
},
"packages": {
"machine": {
"amd64pc": [
"linux-lowlatency",
"linux-tools-lowlatency"
],
"metal": [
"cpufreqd",
"cpufrequtils"
],
"raspi4b": [
"rpi-eeprom"
]
},
"roles": {
"client": [
"nmap"
],
"generic": [
"byobu",
"ncdu",
"neofetch",
"neovim",
"unattended-upgrades"
],
"guardedwire": [
"wireguard"
],
"server": [
"net-tools",
"ufw"
]
},
"system": {
"bionic": [
"python",
"python3-pip"
],
"focal": [
"python-is-python3",
"python3-pip"
],
"groovy": [
"python-is-python3",
"python3-pip"
],
"ubuntu": [
"language-pack-de"
]
}
},
"runcmd": {
"roles": {
"generic": [
"python -m pip install -U pip setuptools wheel"
],
"guardedwire": [
"mkdir /root/wg",
"wg genkey > /root/wg/privatekey",
"wg pubkey > /root/wg/publickey < /root/wg/privatekey",
"ufw allow from 192.168.1.0/24 to any port 51820 proto udp comment 'wireguard'"
],
"server": [
"ufw enable",
"ufw allow out domain",
"ufw allow in domain",
"ufw allow in ssh",
"ufw limit ssh comment 'Limit SSH connections'"
]
}
}
}
no
ethernets The addresses of the next hop router(s) must be specified 'gateway4: 172.16.0.1'
and / or 'gateway6: "2001:4::1"'. Please also specify at least one Nameserver.
The template currently uses the first search domain for it's fqdn generation logic.
map(any)
{
"demo": {
"gateway4": "192.168.1.1",
"nameservers": {
"addresses": [
"192.168.1.1"
],
"search": [
"home.network"
]
}
}
}
no
instances Definition of specific instantiations of this template. There will be a
directory below "output" created with the "hostname" value. Each package
group names specific to "machine", "system" and "roles" will be merged
and the resulting list will be written to the cloud-config "packages" list.
If any of the network's ipv?s lists is empty, the corresponding dhcp? will
be set to true in the generated 'network-data' file. The config map will
be merged on top into the cloud-config file in such a way that you're able
to specify any keys that cloud-init accepts. Any key in this map will in
effect overwrite keys with the same name written by this template.
map(any)
{
"demo": {
"config": {},
"machine": [
"amd64pc",
"netbook"
],
"networks": {
"ethernets": {
"eth0": {
"ipv4s": [],
"ipv6s": []
}
}
},
"netzone": "demo",
"roles": [
"generic",
"client",
"guardedwire"
],
"system": [
"ubuntu",
"focal"
]
}
}
no
locale Cloud-init compatible string to set the locale. string "de_DE.UTF-8" no
matcher Specify machine types which should be matched to your Networking Interface Cards.
This could be everything cloud-init/netplan would accept as a matching expression
like 'driver', 'macaddress' or 'name'. Please extend according to your hardware.
map(any)
{
"kvm": {
"driver": "virtio"
},
"raspi4b": {
"driver": "bcmgenet smsc95xx lan78xx"
}
}
no
ntp Specify if and where to fetch the current time from.
object({
enabled = bool
servers = list(string)
})
{
"enabled": true,
"servers": [
"de.pool.ntp.org"
]
}
no
output Root directory where the generated files will be written to. string "../.output/instances" no
package System package manager options for first boot.
object({
package_update = bool
package_upgrade = bool
package_reboot_if_required = bool
})
{
"package_reboot_if_required": true,
"package_update": true,
"package_upgrade": true
}
no
power_state How the machines should act when cloud-init finishes.
object({
delay = string
mode = string
message = string
timeout = string
condition = string
})
{
"condition": "exit 0",
"delay": "now",
"message": "Finishing...",
"mode": "reboot",
"timeout": "600"
}
no
snap Please state assertions and commands that shall be forwarded to snapd. map(any) {} no
ssh Setting for cloud-init's SSH module. You can e.g. import from launchpad or github.
If you use an SSH key pair you probably want to disable password based ssh login.
object({
ssh_pwauth = bool
ssh_import_id = list(string)
})
{
"ssh_import_id": [],
"ssh_pwauth": true
}
no
structs Define the cloud-init-specific types of data-structures under 'config' to search during user-data generation. list(string)
[
"packages",
"bootcmd",
"runcmd"
]
no
timezone Cloud-init compatible string to set the timezone. string "Europe/Berlin" no
types Define the instance-specific types of data-structures under 'config' to search during user-data generation. list(string)
[
"machine",
"system",
"roles"
]
no
users Access definitions list(any)
[
"default"
]
no
wifis The top level map's keys represent the Wifi's SSID value. map(any)
{
"demo": {}
}
no
write Wether to write everything back to disk. Outputs will always be provided! bool false no

Outputs

Name Description
network-config n/a
static-copy n/a
user-data n/a

About

Using Terraform to build cloud-config and netplan files which can be used to configure bare metal and virtual instances. It uses a subset of capabilities of cloud-init and has been tested with Ubuntu Bionic, Focal and Groovy. You can use it to configure your Raspberry Pi computers all the same as bootstrap your cloud VMs.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published