Executes firstboot and everyboot scripts
https://www.turnkeylinux.org
- Python 54.5%
- Shell 45%
- HTML 0.4%
| .forgejo/workflows | ||
| .github | ||
| bin | ||
| debian | ||
| default | ||
| everyboot.d | ||
| firstboot.d | ||
| lib | ||
| libinithooks | ||
| release_notes | ||
| rsyslog.d | ||
| tests | ||
| turnkey-init-fence/htdocs | ||
| update-motd.d | ||
| .gitignore | ||
| COVERAGE.md | ||
| keel-init | ||
| pyproject.toml | ||
| README.rst | ||
| ruff.toml | ||
| run | ||
| setup.py | ||
| shared-host-keys | ||
| turnkey-init | ||
| turnkey-install-security-updates | ||
| turnkey-sudoadmin | ||
===================================================
System initialization, configuration and preseeding
===================================================
Introduction
============
Before we expose a TurnKey system to a hostile Internet, we first need to
initialize it. This will set passwords, install security updates, configure
key applications settings and disable the "initialization fence".
This initialization process can be interactive or non-interactive depending on
what works best given where and how the system is deployed. By default it is
interactive.
Initialization fence
--------------------
The "initialization fence" - aka 'turnkey-init-fence' - is the mechanism which
blocks access to appliance web services until initialization is complete. It
uses the firewall (via iptables) to redirect attempts to access the local web
services to a static web page served by inithooks/bin/simplehttpd.py.
The default web root is /usr/share/inithooks/htdocs and contains a page which
explains that you need to initialize the system before you can access the web
interfaces. The purpose of the fence is to prevent access to uninitialized web
applications, which in some cases can pose a security risk.
The init-fence runs as a standalone service and is automatically disabled once
initalization is complete.
Interactive system initialization
---------------------------------
A configuration wizard shows a short sequence of simple text dialogs that look
primitive but provide a quick step-by-step process that works anywhere and
requires only the bare minimum of software dependencies - a big advantage for
security sensitive applications:
.. image:: https://www.turnkeylinux.org/files/images/docs/inithooks/turnkey-init-root.png
:alt: root password dialog
:width: 650px
All software is potentially buggy but we can minimize the risk by
intentionally favoring simplicity over fancy eye candy.
The configuration dialogs run in one of two places:
1) **First boot** (console; usually tty1).
On platforms where the user has direct access to a console such as bare
metal (or other ISO install), LXC (Proxmox) and VM/VMDK. The interactive
first boot scripts can be accessed immediately after first boot.
2) **First SSH login** ('root' user or 'admin' on AWS Marketplace).
Systems running on *headless* virtual platforms such as AWS marketplace,
OpenStack and LXC (Proxmox) don't provide the option to interact
with the system at boot time. In that case the interactive first boot
scripts will immediately present once logged in.
Only one run of the configuration dialogs can be in progress at a time. The
first boot run and "keel-init" both hold a lock, /run/inithooks.lock (an
flock the kernel releases when the run exits, however it exits), for as long
as hooks run, and describes itself in it. While another run holds the lock,
"keel-init" refuses (exit status 75) and says where that run is: a first
boot run that asks questions waits on the console ("pct console <ctid>" on
Proxmox, "lxc-console -n <name>" on LXC, or the VM's console), a
"keel-init" left in the dtach session of the first login is reached with
"dtach -a" and its socket, and a preseeded run or the everyboot phase only
has to be waited for. Before the first boot has finished
(RUN_FIRSTBOOT=true and no /run/inithooks-complete), "keel-init" does not
run its own hooks, since under "keel-init" the hooks skip what only a first
boot does: it refuses while inithooks.service is running or queued, and
when nothing will run the first boot (the unit stopped, failed, or skipped
by its condition in a container) it runs /usr/lib/inithooks/run itself,
which does the whole first boot on the operator's terminal. The login
message says the same, from /etc/update-motd.d/06-keel-init, and "run
keel-init" while the initialization fence is up and no run is in progress.
The first boot run itself waits for a "keel-init" that holds the lock.
Non-interactive system initialization
-------------------------------------
The `TurnKey Hub`_ streamlines deployment by preseeding system initialization
settings with values the user provides before launching an instance through the
Hub's cloud deployment web app.
This means when the system boots for the first time it doesn't need to interact
with the user through text dialogs.
Preseeding is well documented and may be used by other hosting providers or
private clouds in a similar way to streamline deployment.
.. _TurnKey Hub: https://hub.turnkeylinux.org/
Preseeding isn't a requirement, just a bonus. Without any special integration,
TurnKey images can be deployed like any other Debian or Debian-based OS and the
will complete the initialization interactively. Non-interactive initialization
is most likely useful for hosting providers, on private cloud infrastructure or
"mass" roll out of multiple TurnKey servers.
Under the hood: everything you wanted to know but were afraid to ask
====================================================================
Most TurnKey users can stop reading here. The above info should be more than
enough for most TurnKey users.
The rest of this documentation is intended for:
- Appliance hackers interested in learning how TurnKey works under the
hood and developing their own configuration hooks.
- Developers who wish to support a new platform that TurnKey doesn't already
support.
- Expert users who want to understand how system initialization works in
depth.
- Hosting providers and private cloud fullstack ninjas interested in
implementing tight integration between TurnKey and custom control panels.
Those particularly interested in automated initialization will fine the
`Preseeding`_ section below of particular interest.
Developing new build types
--------------------------
Appliance development is out of scope for inithooks documentation, but it is
worth noting that if a TurnKey appliance is not preseeded, the system must
provide **one** of the following:
- Direct user access to a system console on first boot (e.g. tty1). The user
can then go though the firstboot scripts interactively. E.g. UI provided by
desktop VM software (such as VirtualBox, VMWare, Hyper-V, etc), a NoVNC
window on Proxmox, a SPICE console or some similar "VNC like" access.
- Facility to set the 'root' (or 'admin'/sudo) user SSH key or password at
launch time (i.e. pre first boot). Note that this is only supported OOTB by
TurnKey "headless" builds. The initihooks package is pre-installed by default
on all TurnKey builds but the package alone does not include the hooks
script/s neccessary. "Headless" builds have the required functionality
enabled at build time. Devs who wish to build TurnKey appliances which are
supported on "headless" systems should use and/or consult the relevant
`Buildtasks`_ scripts for more details. E.g. 'bt-container' (Proxmox/LXC),
'bt-docker', etc.
.. _Buildtasks: https://github.com/turnkeylinux/buildtasks
Inithooks package design goals
------------------------------
The inithooks package executes system initialization scripts which:
- **Regenerate secret keys**: This isn't just a good idea, it's necessary to
avoid man in the middle attacks. Secrets that are (re)generated at
initialization include:
- SSH keys
- SSL/TLS certificates & keys
- Web app DB user passwords. E.g. The password WordPress uses to connect to
the 'wordpress' MariaDB database.
- Other web app secrets, such as session secrets and password salts
- **Set passwords**: Unique user passwords are necessary to avoid the risk
of `hardwired default passwords <https://www.turnkeylinux.org/blog/end-to-default-passwords>`_
- **Configure basic application settings**: Many web apps in the TurnKey
appliance library require settings such as admin email address, application
domain. Having these set at first boot is especially useful and avoids users
needing to manually consult application documentation and hunt down
configuration files.
- **Other system pre-configuration**: Such as setting/resetting an appliance
hostname.
How it works
------------
Inithooks itself is as generic and barebones as possible, leaving the bulk of
functionality to specific "hook" scripts.
The inithooks top-level init script is executed early on in system
initialization. This enables configuration of the system prior to most services
starting. This should be taken into consideration when developing hook scripts.
The hook scripts are located in two sub-directories under /usr/lib/inithooks;
firstboot.d and everyboot.d. As the names suggest, the hook scripts in these
directories will run on first boot (only) and on every boot respectively. On
first boot, scripts in firstboot.d run first, then the scripts in everyboot.d.
The hook scripts in each directory are executed in alphanumeric ordering. This
means a script named 01foo would be executed before 20bar, which would be
executed before 99baz. That's why scripts in these directories have the number
prefixes.
All the TurnKey hook scripts have a 2 digit prefix but any prefix can be used
in theory - although only digits and letters are recommend as the sorting of
special/punctuation characters is not intuitive and may lead to unexpected
results. Inithooks uses the 'sort' command to order the scripts and filenames
will be sorted left to right; digits > uppercase > lowercase. E.g.:
00xxx
01xxx
991xxx
99xxx
ABCxxx
ZZZxxx
zzzxxx
**IMPORTANT**
firstboot.d scripts with a prefix less than 30 should **always** be
non-interactive. E.g. firstboot.d/29foobar should be non-interactive, but
firstboot.d/30barbaz could be interactive. That is because boot log output
will likely overwrite the interactive UI which may make it hard - perhaps
impossible for the user to know what they need to enter.
everyboot.d scripts should **always** be non-interactive.
firstboot.d scripts
'''''''''''''''''''
Scripts in the firstboot.d sub-directory are executed under the
following conditions:
#. If the user executes "keel-init" from a root shell. This command
can be used to rerun the firstboot.d inithooks interactively to
reconfigure the appliance if needed. Certain scripts such as those that
regenerate secret keys are skipped. If developing a hook script that is only
intended to run at first boot - i.e. not when "keel-init" is run, check
the value of the "$_TURNKEY_INIT" env var. When "keel-init" runs, it is
set to 1 - otherwise it should be unset. "turnkey-init" is a link to
"keel-init" and does the same, so that TurnKey's documentation and
existing scripts keep working.
#. When the user logs in as root for the first time into a headless
system. This triggers "keel-init" to run so that the user can
interactively complete appliance initialization.
#. When a TurnKey appliance boots for the first time inithooks checks whether
or not this is the first boot by checking the value of the RUN_FIRSTBOOT
flag in /etc/default/inithooks. If the value is false it runs the scripts
and toggles the flag to true.
The firstboot scripts may run in one of two modes, interactive or
non-interactive, depending on the type of build.
**Non-headless builds** (e.g. installed from ISO):
For these build types unless all values are pre-seeded, the user accesses the
interactive hook scripts directly via the virtual console (usually tty1). They
will be displayed prior to first login and the first script the user will see
is setting the root password. These are the same scripts that get executed if
you run "keel-init" later.
**Headless builds**: (e.g AWS Marketplace, LXC (Proxmox), etc):
These image types can not assume direct user access to the virtual console
during boot and have external mechanisms to set a root password and/or SSH
keys. The first boot has to be capable of running non-interactively, otherwise
we risk hanging the boot while it waits for user interaction that never
happens.
So the system pre-initializes application settings with dummy defaults and sets
all passwords (with the exception of the OS 'root'/'admin' user password) to a
random value.
The output from the non-interactive running of the firstboot scripts is logged
to /var/log/inithooks.log. Inithooks also logs to the systemd journal.
Interactive appliance configuration is delayed until the first time the user
logs in as root. This is accomplished with the help of the
/usr/lib/inithooks/firstboot.d/29preseed hook, which only exists on headless
builds::
#!/bin/bash -e
# generic preseeding of inithooks.conf if it doesn't exist
[ -e $INITHOOKS_CONF ] && exit 0
MASTERPASS=$(mcookie | cut --bytes 1-8)
cat>$INITHOOKS_CONF<<EOF
export ROOT_PASS=$MASTERPASS
export DB_PASS=$MASTERPASS
export APP_PASS=$MASTERPASS
export APP_EMAIL=admin@example.com
export APP_DOMAIN=DEFAULT
export HUB_APIKEY=SKIP
export SEC_ALERTS=SKIP
export SEC_UPDATES=FORCE
export AUTO_RUN=TRUE
EOF
chmod +x /usr/lib/inithooks/firstboot.d/30turnkey-init-fence
**Initialization fence**:
After the user logs in as root/admin and completes the initialization process
the "initialization fence" is stopped and disabled. Users can then access
applications running on the local web server.
firstboot.d/30turnkey-init-fence historically controlled the initfence,
however the fence now runs by default so it's only functionality is to
activate ~$USERNAME/.profile.d/turnkey-init-fence which launches a dtach
session bound to a socket. This ensures that the user is presented with the
interactive initialization hooks when they first log in.
what command are we running in the dtach session?
keel-init -> deactivate initfence (service and profile.d)
everyboot.d scripts
'''''''''''''''''''
Scripts that are in the everyboot.d sub-directory run on every boot. We
try to minimize the number of scripts that live here because they're
basically a poor man's init script and real init scripts via systemd unit files
are generally a superior option.
Setting the root password in a headless deployment
--------------------------------------------------
On headless deployments the user needs to login as root to complete the
appliance initialization process, but how do you login as root?
Not a problem if you're using LXC on ProxMox or a similar system that prompts
you to choose a root password before deploying a TurnKey image.
On AWS or OpenStack you can log in as root with your configured SSH keypair
or retrieve the random root password from the "system log".
Other virtualization / private cloud solutions should be able to use their
existing deployment scripts to set the root password, just like they already do
with Debian and Ubuntu.
Another option is to "preseed" the /etc/inithooks.conf file in the appliance's
filesystem before booting it for the first time. This lets you leverage
inithooks to pre-configure not just the root password but also the database
and application passwords, admin email, domain name, etc.
However note that using preseeding deactivates the "initilization fence". If
you're using preseeding TurnKey assumes you've already interacted with the user
some other way to get the preseeded configuration values.
If you wish to leave the init-fence running when preseeding, include this
additional line in your preseeds file (/etc/inithooks.conf):
export AUTO_RUN=TRUE
That will leave the init-fence running, but it will then need to be manually
disabled:
systemctl disable --now turnkey-init-fence
Preseeding
----------
By default, when an appliance is run for the first time, the firstboot scripts
will prompt the user interactively, through the virtual console, to choose
various passwords and basic application configuration settings.
It is possible to bypass this interactive configuration process by creating
/etc/inithooks.conf in the appliance filesystem and writing inithooks
configuration variables into it before the first system boot. For example::
cat>/etc/inithooks.conf<<EOF
export ROOT_PASS=supersecretrootpass
export DB_PASS=supersecretmysqlpass
export APP_EMAIL=admin@example.com
export APP_PASS=webappadminpassword
export FQDN=blog.example.org
export SEC_ALERTS=admin@example.com
export SEC_UPDATES=FORCE
export HUB_APIKEY=SKIP
EOF
FQDN is the machine's fully qualified domain name (firstboot.d/31fqdn): it
becomes the hostname, the /etc/hosts entry and the name of the self-signed
certificate, and is recorded in the instance description. FQDN=SKIP keeps
the name the machine has.
ROOT_PASS=KEEP keeps the root (or admin) password set before the first
boot, by pct create --password or LXC in the root file system, so an
unattended first boot need not repeat it. It is accepted exactly when the
first boot screen would offer Keep: the image carries its build date
(/etc/keel/build-date), the password is usable and was last changed on or
after it, and it is not the placeholder older images shipped. Otherwise
30rootpass fails with an error in /var/log/inithooks.log, as an invalid
preseed does, and the password is left as it was; KEEP (in any case) is
never set as the password.
This preseeding mechanism makes it relatively easy to integrate TurnKey
with custom control panels, virtualization solutions, etc.
A first boot nobody can answer skips the questions. When the console has
no size (the tty of an LXC container nobody is attached to with pct
console or lxc-console), does not take a write (one nobody reads), or
there is no terminal at all, every hook that would draw a screen asks
nothing and does what it does without an answer, saying so in one line
of /var/log/inithooks.log and the journal (lib/console.sh):
- 30rootpass keeps the password the machine has (pct create --password),
or none;
- 31fqdn keeps the name the machine has and records it in the instance
description when it has a domain;
- 75keel-role and 80keel-cloud leave the node standalone, without a Keel
Cloud key;
- 85secalerts sets no alert email;
- 95secupdates installs the security updates, and 99reboot reboots for a
new kernel, as SEC_UPDATES=FORCE does.
A preseeded value is always used. Run keel-init afterwards to answer what
was skipped.
Don't worry about leaving sensitive passwords in there: after the first boot,
inithooks blanks /etc/inithooks.conf out so important passwords aren't
accidentally left in the clear. Although obviously if the conf file is
included in an image, a malicious actor could read the file from the image.
How exactly you create /etc/inithooks.conf is up to you and the capabilities of
the virtualization platform you are using. For example, many virtualization
platforms provide a facility through which you can run scripts or add files to
the filesystem before the first boot.
TurnKey inithooks does not currently support use with 'cloudinit' which is very
common these days however it is hoped that it will be supported in the not too
distant future.
Declarative preseeding
----------------------
Instead of writing /etc/inithooks.conf by hand, an instance can be described
in a YAML file. At the start of the first boot, the firstboot hook
00declarative validates the description, resolves the secrets it refers to
and writes /etc/inithooks.conf from it. Every later hook reads the same
variables it has always read, so nothing else changes.
Two paths are searched, in this order, and the first one that exists is
read:
1. /etc/keel/instance.yaml, the instance description the operator edits and
the instance tooling writes;
2. /etc/inithooks.yaml.
Both hold the same document, so it does not matter to the reader which one
carries it, and a machine that has only the second keeps working. When both
exist the first wins and the other is named in a warning in the log, so a
description that is being ignored says so instead of being silently passed
over. `declarative.py --which` prints the path that would be read, which is
how the hook asks, and prints nothing when neither is there.
Setting INITHOOKS_DECL in /etc/default/inithooks names the file outright and
no search happens. If no description is found, or if /etc/inithooks.conf
already exists and is not empty, the hook does nothing and the conf file
wins. Unlike the
conf file, the description is not blanked at the end of the first boot: it
holds references to secrets, not the secrets themselves, and it stays on the
instance as a record of what the instance was asked to be.
Example::
version: 1
instance:
hostname: blog
fqdn: blog.example.org
network:
managed_by: host
interfaces:
eth0:
ipv6:
method: static
address: 2001:db8:1::10/64
gateway: fe80::1
ipv4:
method: none
nameservers:
- 2001:4860:4860::8888
secrets:
root_password:
file: /etc/inithooks.secrets.d/root_password
db_password:
generate: true
app_password:
file: /etc/inithooks.secrets.d/app_password
app:
email: admin@example.org
domain: blog.example.org
options: {}
hub:
api_key: skip
security:
alerts: admin@example.org
updates_at_first_boot: force
first_login_wizard: false
preseed: {}
Keys and the variables they produce::
instance.hostname HOSTNAME
instance.fqdn FQDN
secrets.root_password ROOT_PASS
secrets.db_password DB_PASS
secrets.app_password APP_PASS
app.email APP_EMAIL
app.domain APP_DOMAIN
app.options.<key> APP_<KEY>
hub.api_key HUB_APIKEY
security.alerts SEC_ALERTS
security.updates_at_first_boot
SEC_UPDATES
first_login_wizard: true AUTO_RUN=TRUE
network.* IP_CONFIG, IP_ADDRESS, IP_NETMASK, IP_GW,
IP_DNS1, IP_DNS2
preseed.<KEY> <KEY>, exported as written
Notes:
- version is required and must be 1. An unknown top level key is an
error; keys under app.options and preseed are not checked.
- security.updates_at_first_boot controls one thing: whether 95secupdates
installs the pending security updates during the first boot. The
appliance keeps itself current either way, through cron-apt, so the
field is not the machine's update policy and is not named as if it
were. It was called security.updates, which is still read: the old
name renders the same conf and is reported once, with the new name, so
a description written before the rename keeps booting.
- The updates never hold the first boot. 95secupdates gives apt-get
update SEC_UPDATES_UPDATE_TIMEOUT seconds (120) and the whole run
SEC_UPDATES_TIMEOUT seconds (900), both read from the inithooks conf.
A run stopped at its limit, or one that failed, leaves dpkg
configured, says so in one line of the inithooks log and the boot goes
on; cron-apt installs the updates at its daily run.
- A secret is a mapping with exactly one of file or generate. A secret
file is read as bytes, one trailing newline is stripped, and it must
be mode 0600 or stricter and owned by root. generate is meant for
db_password: a generated value is never shown, so it is refused for
root_password and app_password unless first_login_wizard is true.
- Values are shell quoted, so a password containing spaces, quotes or a
dollar sign survives being sourced.
- network.managed_by: host (the default in containers, where the host
writes the interface configuration) means the reader writes no
addresses. It compares the declared addresses with the live ones and
logs an error if they differ, without failing the run.
network.managed_by: file maps the IPv4 settings onto the IP_*
variables read by 01ipconfig; static IPv6 addresses cannot be written
to /etc/network/interfaces yet and are refused.
- tls.acme is accepted and validated (enabled, challenge, domains,
agree_tos, as the instance tooling reads them), but no certificate is
requested at first boot; keel spec apply --system and confconsole's
Let's Encrypt screen request it.
The description can be validated before it is used::
/usr/lib/inithooks/bin/declarative.py --which
/usr/lib/inithooks/bin/declarative.py --check /etc/keel/instance.yaml
/usr/lib/inithooks/bin/declarative.py --render /etc/keel/instance.yaml
--render prints the conf file that would be written, with the secrets
masked.
List of initialization hooks and preseeding configuration parameters
--------------------------------------------------------------------
Below is a list of firstboot hooks. All interactive hooks have preseeding
options to support cloud deployment, hosting and ISV integration.
TurnKey makes every effort to keep this list up to date, but please note that
it may become out of sync.
All of the values noted in the example inithooks.conf above are required if you
desire a completely non-interactive initialization. If they are not pre-seeded,
the user will be asked interactively - which may be problematic in some
scenarios. With the exception of our VPN appliances when a system is
pre-seeded with the above set, any other appliance specific initialization
values that are not set will fall back to "sane" defaults.
Note that secupdates is automatically skipped when in live demo mode.
Most inithooks that are configurable are interactive, however not all.
Non-interactive hooks that can be adjusted via preseeding are marked
below with an asterisk ('*').
Initihook preseed values that are not relevant to a particular appliance or
build will simply be ignored.
Note that almost all appliances have their own application specific
secret-regeneration hooks which will run regardless.
Common to all appliances::
01ipconfig* IP_CONFIG [ dhcp | static | manual ]
IP_ADDRESS, IP_NETMASK, IP_GW, IP_DNS1, IP_DNS2
IP6_CONFIG [ dhcp | static | manual ]
IP6_ADDRESS, IP6_GW, IP6_DNS1, IP6_DNS2
IP6_SLAAC [ yes | no ]
15regen-sslcert DH_BITS [ 1024 | 2048 | 4096 ]
29preseed INITFENCE [ SKIP ]
30rootpass* ROOT_PASS [ KEEP | the password ]
31fqdn FQDN [ SKIP | the name ]
75keel-role database.server.role of the instance description
80keel-cloud HUB_APIKEY [ SKIP | the key ]
85secalerts SEC_ALERTS [ SKIP ]
95secupdates SEC_UPDATES [ SKIP | FORCE ]
Notes on the Keel hooks:
- 31fqdn asks the machine's fully qualified domain name,
blog.example.org, prefilled with the name the machine has (what
"pct create --hostname" set; a dotted name is offered as it is).
The instance description (/etc/keel/instance.yaml, or the file
00declarative read) records instance.hostname and instance.fqdn,
plus tls.acme.domains: [the name] when it declares no domain yet,
so confconsole's Let's Encrypt screen offers it; tls.acme.enabled
is never touched, a hostname declared beside the unchanged name is
kept, and a description the answer does not change is not
rewritten. Then the first label becomes the hostname, set the way
09hostname sets it (lib/hostname.sh: the old name replaced as a
whole name or a first label, never inside another word), and
/etc/hosts gets the entry that makes "hostname -f" answer the name,
rewriting the line a container manager wrote for the host where it
stands. The description comes first so that a step that fails
leaves a description saying what the machine should be. A name
without a domain is kept as the hostname alone, after a notice that
no certificate can be requested without a domain; an empty answer
keeps what the machine has. Lower case labels of letters, digits
and dashes, as a domain name is written; anything else is refused
and asked again. FQDN preseeds the answer (instance.fqdn of the
description renders it, so a described machine is not asked);
FQDN=SKIP asks nothing and changes nothing. keel-init asks again,
prefilled with the fqdn the description declares. The description
is written as confconsole writes it: a copy beside the file,
checked by "keel spec validate --no-secret-files" when keel is
installed, then moved into place; keel has no writer of its own.
- 75keel-role and 80keel-cloud (handbook decision 0020) run
confconsole's first boot screens, /usr/lib/confconsole/keelfirstboot.py,
and do nothing without confconsole. 75keel-role asks this node's
role, standalone (the default), primary or replica, and takes a
primary or a replica through confconsole's Overlay network and
Database mode screens; it is not asked when the instance description
declares database.server.role. 80keel-cloud offers an optional Keel
Cloud API key, kept in /etc/keel/secrets/cloud_api_key (0600) and
referenced as hub.api_key; empty means standalone. It is not asked
when the description declares hub.api_key or HUB_APIKEY is
preseeded, and a preseeded key is stored without a screen. It
replaces TurnKey's 80hub-services, which linked TKLBAM and HubDNS to
the TurnKey Hub. keel-init asks both again.
Notes:
- 01ipconfig writes /etc/network/interfaces for eth0 (br0 in an LXC
build) from the IP_* and IP6_* keys and brings the interface up. It
does nothing unless IP_CONFIG or IP6_CONFIG is set.
IP_CONFIG selects the IPv4 method. With static, IP_ADDRESS and
IP_NETMASK are required; IP_GW, IP_DNS1 and IP_DNS2 are optional.
IP6_CONFIG selects the IPv6 method and defaults to dhcp, which keeps
IPv6 on SLAAC or DHCPv6 as the image ships it. With static,
IP6_ADDRESS is required and carries the prefix length; IP6_GW is
optional (a link-local gateway such as fe80::1 is accepted); IP6_DNS1
and IP6_DNS2 are optional resolvers. The address and the gateway must
be IPv6: an IPv4 address, a missing prefix length, a multicast or
loopback address is a fatal error and nothing is written. A resolver
may be of either family, since resolvconf takes dns-nameservers from
any stanza: with IPv4 on dhcp, the inet6 stanza is where its
resolvers can be written. When only IP6_* keys are set, IPv4 stays on
dhcp.
A static inet6 stanza keeps SLAAC, so the interface also takes an
address from the router's advertisements. IP6_SLAAC=no (default yes)
makes the static address the only one: the stanza turns autoconf off
on the interface before the address is added (pre-up) and back on
when it goes down (post-down). accept_ra stays on, so the router's
routes are kept. IP6_SLAAC=no requires IP6_CONFIG=static.
A static IPv6 address with IPv4 left on dhcp::
cat>/etc/inithooks.conf<<EOF
export IP6_CONFIG=static
export IP6_ADDRESS=2001:db8:1::10/64
export IP6_GW=fe80::1
export IP6_DNS1=2001:db8:1::53
export IP6_DNS2=2001:db8:2::53
export IP6_SLAAC=no
EOF
Static addresses on both families::
cat>/etc/inithooks.conf<<EOF
export IP6_CONFIG=static
export IP6_ADDRESS=2001:db8:1::10/64
export IP6_GW=2001:db8:1::1
export IP6_DNS1=2001:db8:1::53
export IP_CONFIG=static
export IP_ADDRESS=192.0.2.10
export IP_NETMASK=255.255.255.0
export IP_GW=192.0.2.1
export IP_DNS1=192.0.2.53
EOF
- DH_BITS refers to the number of bits used when generating Diffie-Hellman
parameters used in TLS (i.e. HTTPS) _`Diffie-Hellman key exchange`. It
is a legacy feature as modern SSL/TLS encryption now either uses a
pre-set value (TLS1.2) or does not use generated Diffie-Hellman values at
all (TLS1.3).
- In LXC builds, the container root password is set via the host at
creation time. As such, 30rootpass is disabled and ROOT_PASS does not
apply. In other headless builds it is still enabled and can be preseeded.
Even if SSH keys are preconfigured, a root password will still be asked
for as it is required to log in to Webmin.
Appliance specific::
35mysqlpass DB_PASS
35pgsqlpass DB_PASS
40ansible APP_PASS
40couchdb APP_PASS
40espocrm APP_PASS
40etherpad APP_PASS
40githttp APP_PASS
40icesecretset APP_PASS
40jenkins APP_PASS
40mediawiki APP_PASS
40mibew APP_PASS
40mongodb APP_PASS
40moodle APP_PASS
40mumblesupw APP_PASS
40observium APP_PASS
40odoo APP_PASS
40openvas APP_PASS
40orangehrm APP_PASS
40otrs APP_PASS
40phpmumbleadmin APP_PASS
40plone APP_PASS
40sugarcrm APP_PASS
40suitecrm APP_PASS
40torrentserver APP_PASS
40trac APP_PASS
40typo3 APP_PASS
40zoneminder APP_PASS
40redis APP_PASS [, APP_IP_BIND, APP_PROTECTED]
40nextcloud APP_PASS, APP_DOMAIN
40openldap APP_PASS, APP_DOMAIN
40owncloud APP_PASS, APP_DOMAIN
40zurmo APP_PASS, APP_DOMAIN
40domain-controller APP_PASS, APP_DOMAIN [, APP_REALM, APP_JOIN, APP_JOIN_NS]]
40b2evolution APP_PASS, APP_EMAIL
40collabtive APP_PASS, APP_EMAIL
40concrete5 APP_PASS, APP_EMAIL
40django APP_PASS, APP_EMAIL
40dokuwiki APP_PASS, APP_EMAIL
40drupal7 APP_PASS, APP_EMAIL
40e107 APP_PASS, APP_EMAIL
40ezplatform APP_PASS, APP_EMAIL
40foodsoft APP_PASS, APP_EMAIL
40gallery APP_PASS, APP_EMAIL
40joomla APP_PASS, APP_EMAIL
40kliqqi APP_PASS, APP_EMAIL
40limesurvey APP_PASS, APP_EMAIL
40mahara APP_PASS, APP_EMAIL
40mambo APP_PASS, APP_EMAIL
40mantis APP_PASS, APP_EMAIL
40mattermost APP_PASS, APP_EMAIL
40mayan APP_PASS, APP_EMAIL
40moinmoin APP_PASS, APP_EMAIL
40omeka APP_PASS, APP_EMAIL
40oscommerce APP_PASS, APP_EMAIL
40phpbb APP_PASS, APP_EMAIL
40processmaker APP_PASS, APP_EMAIL
40redmine APP_PASS, APP_EMAIL
40roundup APP_PASS, APP_EMAIL
40silverstripe APP_PASS, APP_EMAIL
40simpleinvoices APP_PASS, APP_EMAIL
40sitracker APP_PASS, APP_EMAIL
40twiki APP_PASS, APP_EMAIL
40ushahidi APP_PASS, APP_EMAIL
40vanilla APP_PASS, APP_EMAIL
40vtiger APP_PASS, APP_EMAIL
40wordpress APP_PASS, APP_EMAIL
40xoops APP_PASS, APP_EMAIL
40canvas APP_PASS, APP_EMAIL, APP_DOMAIN
40drupal8 APP_PASS, APP_EMAIL, APP_DOMAIN
40elgg APP_PASS, APP_EMAIL, APP_DOMAIN
40foswiki APP_PASS, APP_EMAIL, APP_DOMAIN
40gitlab APP_PASS, APP_EMAIL, APP_DOMAIN
40gnusocial APP_PASS, APP_EMAIL, APP_DOMAIN
40icescrum APP_PASS, APP_EMAIL, APP_DOMAIN
40matomo APP_PASS, APP_EMAIL, APP_DOMAIN
40phplist APP_PASS, APP_EMAIL, APP_DOMAIN
40opencart APP_PASS, APP_EMAIL, APP_DOMAIN
40prestashop APP_PASS, APP_EMAIL, APP_DOMAIN
40punbb APP_PASS, APP_EMAIL, APP_DOMAIN
40simplemachines APP_PASS, APP_EMAIL, APP_DOMAIN
40zencart APP_PASS, APP_EMAIL, APP_DOMAIN
40magento APP_PASS, APP_EMAIL, APP_DOMAIN [, APP_PRIVKEY, APP_PUBKEY]
40bugzilla APP_PASS, APP_EMAIL [, APP_OUTMAIL]
40ghost APP_PASS, APP_EMAIL, APP_DOMAIN [, APP_UNAME]
Fileserver appliance specific - LXC only::
35samba-container APP_PASS
Linux and Samba user management is separate and discrete. Previously by default
Samba users were mapped 1-1 with Linux users and Samba supported syncronization
of passwords between the Linux and Samba users (so essentially the difference
between the 2 user management systems was hidden from the end user). However
due to a significant security issue, this module has been removed. Samba4 has
moved to prioritize support for AD integration (which uses a different
paradigm - all Samba users are contained within a single Linux user account).
To somewhat work around this limitation, on the TurnKey Fileserver appliance,
when you set the root (Linux) user password, the Samba root user password is
also set. However for an LXC container, the root password is set on the host,
not the guest. So this workaround is not possible. Hence the Samba root
password must be set separately.
Development notes
-----------------
So you're creating a new appliance and want to add initialization
hooks. Awesome! Here are some examples to get you going.
Non-interactive inithook
''''''''''''''''''''''''
The following example is used in the Joomla3 appliance. It
regenerates the *secret*, and sets a random mysql password for the
joomla user::
/usr/lib/inithooks/firstboot.d/20regen-joomla-secrets
#!/bin/bash -e
# regenerate joomla secret key and mysql password
. /etc/default/inithooks
updateconf() {
CONF=/var/www/joomla/configuration.php
sed -i "s/var $1 = \(.*\)/var $1 = '$2';/" $CONF
}
updateconf '\$secret' $(mcookie)$(mcookie)
PASSWORD=$(mcookie)
updateconf '\$password' $PASSWORD
$INITHOOKS_PATH/bin/mysqlconf.py --user=joomla --pass="$PASSWORD"
Interactive inithook
''''''''''''''''''''
The following example is used to set the root password in all appliances -
with the exception of headless builds where the password/keys should be
configured pre-launch. If ROOTPASS is not set, the user will be asked to enter
a password interactively.
.. note::
A *very* basic debugging setup is present in dialog_wrapper.
If you're getting odd or unexpected output, dialogs you're expecting
to see are not present or are generally paranoid about the quality
of your code you can enable debug logging by setting the environment
variable ``DIALOG_DEBUG``.
When set debugging output will be written to ``/var/log/dialog.log``
::
/usr/lib/inithooks/firstboot.d/30rootpass
#!/bin/bash -e
# set root password
. /etc/default/inithooks
[ -e $INITHOOKS_CONF ] && . $INITHOOKS_CONF
$INITHOOKS_PATH/bin/setpasspass.py root --pass="$ROOTPASS"
::
/usr/lib/inithooks/bin/setpass.py
#!/usr/bin/python3
# Copyright (c) 2010 Alon Swartz <alon@turnkeylinux.org>
"""Set account password
Arguments:
username username of account to set password for
Options:
-p --pass= if not provided, will ask interactively
"""
import sys
import getopt
import subprocess
from subprocess import PIPE
from libinithooks.dialog_wrapper import Dialog
def fatal(s):
print >> sys.stderr, "Error:", s
sys.exit(1)
def usage(e=None):
if e:
print >> sys.stderr, "Error:", e
print >> sys.stderr, "Syntax: %s <username> [options]" % sys.argv[0]
print >> sys.stderr, __doc__
sys.exit(1)
def main():
try:
opts, args = getopt.gnu_getopt(sys.argv[1:], "hp:", ['help', 'pass='])
except getopt.GetoptError, e:
usage(e)
if len(args) != 1:
usage()
username = args[0]
password = ""
for opt, val in opts:
if opt in ('-h', '--help'):
usage()
elif opt in ('-p', '--pass'):
password = val
if not password:
d = Dialog('TurnKey GNU/Linux - First boot configuration')
password = d.get_password(
"%s Password" % username.capitalize(),
"Please enter new password for the %s account." % username)
command = ["chpasswd"]
input = ":".join([username, password])
p = subprocess.Popen(command, stdin=PIPE, shell=False)
p.stdin.write(input)
p.stdin.close()
err = p.wait()
if err:
fatal(err)
if __name__ == "__main__":
main()
.. _Diffie-Hellman key exchange: https://en.wikipedia.org/wiki/Diffie-Hellman_key_exchange