CoreOS allows you to declaratively customize various OS-level items, such as network configuration, user accounts, and systemd units. This document describes the full list of items we can configure. The coreos-cloudinit
program uses these files as it configures the OS after startup or during runtime.
Your cloud-config is processed during each boot. Invalid cloud-config won't be processed but will be logged in the journal. You can validate your cloud-config with the CoreOS online validator or by running coreos-cloudinit -validate
. In addition to these two validation methods you can debug coreos-cloudinit
system output through the journalctl
tool:
journalctl --identifier=coreos-cloudinit
It will show coreos-cloudinit
run output which was triggered by system boot.
The file used by this system initialization program is called a "cloud-config" file. It is inspired by the cloud-init project's cloud-config file, which is "the defacto multi-distribution package that handles early initialization of a cloud instance" (cloud-init docs). Because the cloud-init project includes tools which aren't used by CoreOS, only the relevant subset of its configuration items will be implemented in our cloud-config file. In addition to those, we added a few CoreOS-specific items, such as etcd configuration, OEM definition, and systemd units.
We've designed our implementation to allow the same cloud-config file to work across all of our supported platforms.
The cloud-config file uses the YAML file format, which uses whitespace and new-lines to delimit lists, associative arrays, and values.
A cloud-config file must contain a header: either #cloud-config
for processing as cloud-config (suggested) or #!
for processing as a shell script (advanced). If cloud-config has the #cloud-config
header, it should followed by an associative array which has zero or more of the following keys:
coreos
ssh_authorized_keys
hostname
users
write_files
manage_etc_hosts
The expected values for these keys are defined in the rest of this document.
If cloud-config header starts on #!
then coreos-cloudinit will recognize it as shell script which is interpreted by bash and run it as transient systemd service.
CoreOS tries to conform to each platform's native method to provide user data. Each cloud provider tends to be unique, but this complexity has been abstracted by CoreOS. You can view each platform's instructions on their documentation pages. The most universal way to provide cloud-config is via config-drive, which attaches a read-only device to the machine, that contains your cloud-config file.
The coreos.etcd.*
parameters will be translated to a partial systemd unit acting as an etcd configuration file.
If the platform environment supports the templating feature of coreos-cloudinit it is possible to automate etcd configuration with the $private_ipv4
and $public_ipv4
fields. For example, the following cloud-config document...
#cloud-config
coreos:
etcd:
name: "node001"
# generate a new token for each unique cluster from https://discovery.etcd.io/new
discovery: "https://discovery.etcd.io/<token>"
# multi-region and multi-cloud deployments need to use $public_ipv4
addr: "$public_ipv4:4001"
peer-addr: "$private_ipv4:7001"
...will generate a systemd unit drop-in for etcd.service with the following contents:
[Service]
Environment="ETCD_NAME=node001"
Environment="ETCD_DISCOVERY=https://discovery.etcd.io/<token>"
Environment="ETCD_ADDR=203.0.113.29:4001"
Environment="ETCD_PEER_ADDR=192.0.2.13:7001"
For more information about the available configuration parameters, see the etcd documentation.
Note: The $private_ipv4
and $public_ipv4
substitution variables referenced in other documents are only supported on Amazon EC2, Google Compute Engine, OpenStack, Rackspace, DigitalOcean, and Vagrant.
The coreos.etcd2.*
parameters will be translated to a partial systemd unit acting as an etcd configuration file.
If the platform environment supports the templating feature of coreos-cloudinit it is possible to automate etcd configuration with the $private_ipv4
and $public_ipv4
fields. When generating a discovery token, set the size
parameter, since etcd uses this to determine if all members have joined the cluster. After the cluster is bootstrapped, it can grow or shrink from this configured size.
For example, the following cloud-config document...
#cloud-config
coreos:
etcd2:
# generate a new token for each unique cluster from https://discovery.etcd.io/new?size=3
discovery: "https://discovery.etcd.io/<token>"
# multi-region and multi-cloud deployments need to use $public_ipv4
advertise-client-urls: "http://$public_ipv4:2379"
initial-advertise-peer-urls: "http://$private_ipv4:2380"
# listen on both the official ports and the legacy ports
# legacy ports can be omitted if your application doesn't depend on them
listen-client-urls: "http://0.0.0.0:2379,http://0.0.0.0:4001"
listen-peer-urls: "http://$private_ipv4:2380,http://$private_ipv4:7001"
...will generate a systemd unit drop-in for etcd2.service with the following contents:
[Service]
Environment="ETCD_DISCOVERY=https://discovery.etcd.io/<token>"
Environment="ETCD_ADVERTISE_CLIENT_URLS=http://203.0.113.29:2379"
Environment="ETCD_INITIAL_ADVERTISE_PEER_URLS=http://192.0.2.13:2380"
Environment="ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379,http://0.0.0.0:4001"
Environment="ETCD_LISTEN_PEER_URLS=http://192.0.2.13:2380,http://192.0.2.13:7001"
For more information about the available configuration parameters, see the etcd2 documentation.
Note: The $private_ipv4
and $public_ipv4
substitution variables referenced in other documents are only supported on Amazon EC2, Google Compute Engine, OpenStack, Rackspace, DigitalOcean, and Vagrant.
The coreos.fleet.*
parameters work very similarly to coreos.etcd2.*
, and allow for the configuration of fleet through environment variables. For example, the following cloud-config document...
#cloud-config
coreos:
fleet:
public-ip: "$public_ipv4"
metadata: "region=us-west"
...will generate a systemd unit drop-in like this:
[Service]
Environment="FLEET_PUBLIC_IP=203.0.113.29"
Environment="FLEET_METADATA=region=us-west"
List of fleet configuration parameters:
For more information on fleet configuration, see the fleet documentation.
The coreos.flannel.*
parameters also work very similarly to coreos.etcd2.*
and coreos.fleet.*
. They can be used to set environment variables for
flanneld. For example, the following cloud-config...
#cloud-config
coreos:
flannel:
etcd_prefix: "/coreos.com/network2"
...will generate a systemd unit drop-in like so:
[Service]
Environment="FLANNELD_ETCD_PREFIX=/coreos.com/network2"
List of flannel configuration parameters:
For more information on flannel configuration, see the flannel documentation.
The coreos.locksmith.*
parameters can be used to set environment variables
for locksmith. For example, the following cloud-config...
#cloud-config
coreos:
locksmith:
endpoint: "http://example.com:2379"
...will generate a systemd unit drop-in like so:
[Service]
Environment="LOCKSMITHD_ENDPOINT=http://example.com:2379"
List of locksmith configuration parameters:
For the complete list of locksmith configuration parameters, see the locksmith documentation.
The coreos.update.*
parameters manipulate settings related to how CoreOS instances are updated.
These fields will be written out to and replace /etc/coreos/update.conf
. If only one of the parameters is given it will only overwrite the given field.
The reboot-strategy
parameter also affects the behaviour of locksmith.
Note: cloudinit will only manipulate the locksmith unit file in the systemd runtime directory (/run/systemd/system/locksmithd.service
). If any manual modifications are made to an overriding unit configuration file (e.g. /etc/systemd/system/locksmithd.service
), cloudinit will no longer be able to control the locksmith service unit.
#cloud-config
coreos:
update:
reboot-strategy: "etcd-lock"
The coreos.units.*
parameters define a list of arbitrary systemd units to start after booting. This feature is intended to help you start essential services required to mount storage and configure networking in order to join the CoreOS cluster. It is not intended to be a Chef/Puppet replacement.
Each item is an object with the following fields:
--runtime
argument to systemctl enable
. The default value is false.systemctl enable <name>
. The default value is false./dev/null
(analogous to systemctl mask <name>
). Note that unlike systemctl mask
, this will destructively remove any existing unit file located at /etc/systemd/system/<unit>
, to ensure that the mask succeeds. The default value is false.NOTE: The command field is ignored for all network, netdev, and link units. The systemd-networkd.service unit will be restarted in their place.
Write a unit to disk, automatically starting it.
#cloud-config
coreos:
units:
- name: "docker-redis.service"
command: "start"
content: |
[Unit]
Description=Redis container
Author=Me
After=docker.service
[Service]
Restart=always
ExecStart=/usr/bin/docker start -a redis_server
ExecStop=/usr/bin/docker stop -t 2 redis_server
Add the DOCKER_OPTS environment variable to docker.service.
#cloud-config
coreos:
units:
- name: "docker.service"
drop-ins:
- name: "50-insecure-registry.conf"
content: |
[Service]
Environment=DOCKER_OPTS='--insecure-registry="10.0.1.0/24"'
Start the built-in etcd2
and fleet
services:
#cloud-config
coreos:
units:
- name: "etcd2.service"
command: "start"
- name: "fleet.service"
command: "start"
The ssh_authorized_keys
parameter adds public SSH keys which will be authorized for the core
user.
The keys will be named "coreos-cloudinit" by default.
Override this by using the --ssh-key-name
flag when calling coreos-cloudinit
.
#cloud-config
ssh_authorized_keys:
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0g+ZTxC7weoIJLUafOgrm+h..."
The hostname
parameter defines the system's hostname.
This is the local part of a fully-qualified domain name (i.e. foo
in foo.example.com
).
#cloud-config
hostname: "coreos1"
The users
parameter adds or modifies the specified list of users. Each user is an object which consists of the following fields. Each field is optional and of type string unless otherwise noted.
All but the passwd
and ssh-authorized-keys
fields will be ignored if the user already exists.
The following fields are not yet implemented:
#cloud-config
users:
- name: "elroy"
passwd: "$6$5s2u6/jR$un0AvWnqilcgaNB3Mkxd5yYv6mTlWfOoCYHZmfi3LDKVltj.E8XNKEcwWm..."
groups:
- "sudo"
- "docker"
ssh-authorized-keys:
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0g+ZTxC7weoIJLUafOgrm+h..."
If you choose to use a password instead of an SSH key, generating a safe hash is extremely important to the security of your system. Simplified hashes like md5crypt are trivial to crack on modern GPU hardware. Here are a few ways to generate secure hashes:
# On Debian/Ubuntu (via the package "whois")
mkpasswd --method=SHA-512 --rounds=4096
# OpenSSL (note: this will only make md5crypt. While better than plantext it should not be considered fully secure)
openssl passwd -1
# Python (change password and salt values)
python -c "import crypt, getpass, pwd; print crypt.crypt('password', '\$6\$SALT\$')"
# Perl (change password and salt values)
perl -e 'print crypt("password","\$6\$SALT\$") . "\n"'
Using a higher number of rounds will help create more secure passwords, but given enough time, password hashes can be reversed. On most RPM based distributions there is a tool called mkpasswd available in the expect
package, but this does not handle "rounds" nor advanced hashing algorithms.
The write_files
directive defines a set of files to create on the local filesystem.
Each item in the list may have the following keys:
path
<user>:<group>
argument to chown <user>:<group> <path>
.#cloud-config
write_files:
- path: "/etc/resolv.conf"
permissions: "0644"
owner: "root"
content: |
nameserver 8.8.8.8
- path: "/etc/motd"
permissions: "0644"
owner: "root"
content: |
Good news, everyone!
- path: "/tmp/like_this"
permissions: "0644"
owner: "root"
encoding: "gzip"
content: !!binary |
H4sIAKgdh1QAAwtITM5WyK1USMqvUCjPLMlQSMssS1VIya9KzVPIySwszS9SyCpNLwYARQFQ5CcAAAA=
- path: "/tmp/or_like_this"
permissions: "0644"
owner: "root"
encoding: "gzip+base64"
content: |
H4sIAKgdh1QAAwtITM5WyK1USMqvUCjPLMlQSMssS1VIya9KzVPIySwszS9SyCpNLwYARQFQ5CcAAAA=
- path: "/tmp/todolist"
permissions: "0644"
owner: "root"
encoding: "base64"
content: |
UGFjayBteSBib3ggd2l0aCBmaXZlIGRvemVuIGxpcXVvciBqdWdz
The manage_etc_hosts
parameter configures the contents of the /etc/hosts
file, which is used for local name resolution.
Currently, the only supported value is "localhost" which will cause your system's hostname
to resolve to "127.0.0.1". This is helpful when the host does not have DNS
infrastructure in place to resolve its own hostname, for example, when using Vagrant.
#cloud-config
manage_etc_hosts: "localhost"