install.fairie/docs/customization/secrets.md
Brian Zalewski 7359228e43 Latest
2023-11-27 18:41:42 +00:00

53 KiB

title description sidebar_label slug
Integrating Secrets Discover how to leverage the incredibly useful but optional integrations that Install Doctor supports by integrating variables in the form of environment variables and encrypted secrets into your own custom fork. Secrets /customization/secrets

Install Doctor implements many optional features that rely on user-specific variables. Most of these user-specific variables are API keys. To augment that capabilities of your device, Install Doctor can leverage API keys to many free and popular cloud services. These API keys, as well as other user-specific variables, can be utilized by defining them as environment variables prior to running the start script. It is also possible to encrypt and bundle some of these secrets into your own fork of the Install Doctor repository.

Environment Variables

The easiest way to get started with automating the Install Doctor provisioning process and leveraging optional features is to define user-specific variables as environment variables.

For instance, if you want to automate the provisioning process the first time you run the Install Doctor quick start script (without deep diving into all the variables yet), you can run the following (depending on your operating system):

Linux / macOS:

export HEADLESS_INSTALL=true
export SOFTWARE_GROUP=Standard-Desktop
export FULL_NAME="Joe Shmoe"
export PRIMARY_EMAIL="help@megabyte.space"
export PUBLIC_SERVICES_DOMAIN="megabyte.space"
export START_REPO=my-gh-user/my-fork-name
bash <(curl -sSL https://install.doctor/start)

Windows:

$env:HEADLESS_INSTALL = true
$env:SOFTWARE_GROUP = Standard-Desktop
$env:FULL_NAME = 'Joe Shmoe'
$env:PRIMARY_EMAIL = 'help@megabyte.space'
$env:PUBLIC_SERVICES_DOMAIN = 'megabyte.space'
$env:START_REPO = 'my-gh-user/my-fork-name'
iex ((New-Object System.Net.WebClient).DownloadString('https://install.doctor/windows'))

Qubes:

export HEADLESS_INSTALL=true
export SOFTWARE_GROUP=Standard-Desktop
export FULL_NAME="Joe Shmoe"
export PRIMARY_EMAIL="help@megabyte.space"
export PUBLIC_SERVICES_DOMAIN="megabyte.space"
export START_REPO=my-gh-user/my-fork-name
qvm-run --pass-io sys-firewall "curl -sSL https://install.doctor/qubes" > ~/setup.sh
bash ~/setup.sh

Running the blocks of code listed above will bypass the Install Doctor TUI prompt system, allowing a completely headless setup process for your device.

There are many other variables you can make use of which are detailed in one of the following sections below.

Encrypted Secrets

For added security and convienience, Install Doctor supports embedding your secret variables into your own fork of Install Doctor by encrypting them with the Chezmoi default encryption provider called Age. By using this method, you will no longer have to manage a long set of environment variables and you will be able to store your encrypted secrets in a public git that you can use to provision any of your devices.

The first thing you should do when leveraging your own Age encryption key in your own fork of Install Doctor is to delete all the keys stored in the home/.chezmoitemplates/secrets/ folder. If you do not do this, then Install Doctor will try unencrypting the test secrets using your key.

Creating an Age Key (Password Protected)

Install Doctor's default recommended encryption method involves:

  1. Creating a password protected Age encryption key
  2. Using the encryption key to encrypt your variables which are stored in home/.chezmoitemplates/secrets/

To create an encryption key, first ensure Age is installed and available in your PATH (the quick start script will automatically install Homebrew / Age). With age available from your terminal, run the following:

age-keygen | age -p > key.age

The output should look something like the following if you decided to forego creating a custom password:

Public key: age1wzpkjhk6jtgq2d3q97jdq7ptwpra7kdplnt38p5ruetcwfzahvps40l6a5
age: using autogenerated passphrase "act-client-permit-coil-clinic-cushion-wheat-beauty-ski-alarm"

Make note of the public key and your password. The public key should be added to the home/.chezmoi.yaml.tmpl file under the age.recipient key (just search for, "recipient" in the file). The key.age file that was generated should be added to home/key.txt.age. The quick start script that Install Doctor hosts expects the key to be stored in home/key.txt.age.

With all of this done, you can commit your changes. Your key.txt.age file is useless to anyone who does not know the password to decrypt it. The Install Doctor start script (that you can find on the homepage) will prompt you to decrypt the key.txt.age file using your selected password and store it in the location specified in the home/.chezmoi.yaml.tmpl file. For automation purposes, if you are using the default home/.chezmoi.yaml.tmpl file settings, the unencrypted file is temporarily stored on the disk in the ~/.config/age/chezmoi.txt location. This makes it easier to re-run the provisioning process and add new secrets to your custom fork. After you are done using the encryption key, you should delete the unencrypted Age key file stored at ~/.config/age/chezmoi.txt.

Adding Secrets Using the Age Key

To add secrets to your custom fork, you need to ensure Chezmoi is configured to use the file stored in ~/.config/age/chezmoi.txt that is decrypted using a password from the file stored in home/key.txt.age of your custom fork. The easiest way to do this for the first time is to ensure the START_REPO environment variable is pointing to your custom fork and run the quick start script:

Linux / macOS:

export START_REPO=my-gh-user/my-fork-name
bash <(curl -sSL https://install.doctor/start)

Windows:

$env:START_REPO = 'my-gh-user/my-fork-name'
iex ((New-Object System.Net.WebClient).DownloadString('https://install.doctor/windows'))

Qubes:

export START_REPO=my-gh-user/my-fork-name
qvm-run --pass-io sys-firewall "curl -sSL https://install.doctor/qubes" > ~/setup.sh
bash ~/setup.sh

Early in the provisioning process, the script will prompt you for your Age encryption passphrase. After this happens, you can CTRL+C out of the script and begin adding your encrypted secrets to your git repository fork.

With Chezmoi and Age configured, you can now begin encrypting all the pieces of data that you do not want to have to pass in as environment variables. You can also encrypt other things like SSH keys, GPG keys, etc.

Encrypting an API Key

To encrypt an API key, you would run:

echo "apikey-xXxxXxX" | chezmoi encrypt

The resulting text that outputs to the terminal would look something like this:

-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCamNtb0pvOFRmYXRyNEhY
R1BpS09IYVBSSG83Rmh2MVJpdExKdjZrY2hVCmRmTTdjUDJyU2ZZK0NObmUwZ0dH
eGtFQUV6NXVPdjR1WFljNUkyczZuVjAKLS0tIDVTZDFPLytQVTJMNStUK21KYVF4
QVBhb0hIMG9tRjVuYWlHejN4cDJrQkkKTx7EQBmWL+0mXeaOOAtqo9rbJjWYx7mj
Jr4Trf/qfrmiDXX/
-----END AGE ENCRYPTED FILE-----

Copy the text including the lines that contain BEGIN AGE ENCRYPTED FILE and END AGE ENCRYPTED FILE and store them into the appropriate file nested inside home/.chezmoitemplates/secrets/. You can determine the supported key file names by referring to the Supported Variables / Secrets Table below.

Encrypting a File

To encrypt an entire file (named myfile.ext in the following example), you can run:

chezmoi encrypt myfile.ext

The resulting encrypted text can then be copied / pasted into the appropriate key file location. Supported targets are listed below in the Supported Variables / Secrets Table section.

Using GPG

If you prefer to use GPG instead of Age as your encryption mechanism, you can define this option in the home/.chezmoi.yaml.tmpl file. For more details on this implementation, see the GPG page in the Chezmoi docs.

Users may want to do this so they can protect their secrets with hardware-backed encryption via devices like a YubiKey. For details on how to setup GPG with a YubiKey, refer to this guide.

Supported Variables / Secrets Table

The following table details all the custom variables supported by Install Doctor. The variable column denotes the name of the environment variable that can be specified to enable the automated deployment and the description details where the variable is used along with relevant details.

Unless otherwise specified in the description column, all of the variables in this chart can be stored as secrets by saving the encrypted secret environment variable in the home/.chezmoitemplates/secrets/ folder (with a file name equal to the environment variable name). So, if you wanted to saved your GITHUB_TOKEN as an encrypted secret in your fork then you would encrypt following the instructions detailed above and then saved the encrypted secret in the home/.chezmoitemplates/secrets/GITHUB_TOKEN location (e.g. echo "MY_GITHUB_API_TOKEN" | chezmoi encrypt > "home/.chezmoitemplates/secrets/GITHUB_TOKEN").

Variable Description
AGE_PASSWORD Automate the Chezmoi Age decryption process by passing in the passphrase for the key.txt.age file stored in the home/ folder (which is used to encrypt all your secrets). This variable can only be passed in as an environment variable.
ANSIBLE_GALAXY_TOKEN Ansible Galaxy API token stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
ANSIBLE_VAULT_PASSWORD Ansible Vault password stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
APPLE_USERNAME Username of your Apple developer account which is assigned to the XCODES_USERNAME variable for automated use of the Xcodes CLI and app
APPLE_PASSWORD Password of your Apple developer account which is assigned to the XCODES_PASSWORD variable for automated use of the Xcodes CLI and app
ATUIN_EMAIL E-mail address used for registering with Atuin
ATUIN_PASSWORD Password used for registering with Atuin
ATUIN_USERNAME Username used for registering with Atuin
AWS_ACCESS_KEY_ID AWS access key ID (used for storing / retrieving from AWS Secret Manager which is used for headless Xcode installations / developer account authentications)
AWS_DEFAULT_REGION Default AWS region to use when region is not passed in via commands (e.g. us-east-1)
AWS_SECRET_ACCESS_KEY AWS access key secret (used in conjunction with the AWS_ACCESS_KEY_ID)
CLOUDFLARE_API_KEY CloudFlare administration API key. Used by CloudFlare CLI.
CLOUDFLARE_ACCOUNT_ID The CloudFlare account ID
CLOUDFLARE_ORIGIN_CA_KEY The CloudFlare origin CA key (currently unused)
CLOUDFLARE_R2_ID The CloudFlare R2 read / edit access key ID used for mounting S3-compliant buckets to various locations such as /mnt/s3-public, /mnt/s3-private, and ~/.local/mnt/s3 via rclone. The configuration files are located in ~/.config/rclone/ when CLOUDFLARE_R2_SECRET and .user.cloudflare.r2 in .chezmoi.yaml are defined.
CLOUDFLARE_R2_SECRET The CloudFlare R2 read / edit secret access key used for mounting S3-compliant buckets to various locations such as /mnt/s3-public, /mnt/s3-private, and ~/.local/mnt/s3 via rclone. The configuration files are located in ~/.config/rclone/ when CLOUDFLARE_R2_ID and .user.cloudflare.r2 in .chezmoi.yaml are defined.
CLOUDFLARE_TEAMS_CLIENT_ID CloudFlare Teams client ID used to automatically connect to CloudFlare Teams network via warp-cli when CLOUDFLARE_TEAMS_CLIENT_SECRET is also available. You can acquire the secret from a CloudFlare Teams service token. See this article.
CLOUDFLARE_TEAMS_CLIENT_SECRET CloudFlare Teams client secret used to automatically connect to CloudFlare Teams network via warp-cli when CLOUDFLARE_TEAMS_CLIENT_ID is also available. You can acquire the ID from a CloudFlare Teams service token. See this article.
CLOUDFLARE_TEAMS_ORG The organization name used to connect to CloudFlare WARP Teams Zero Trust automatically. Used to populate the organization value referenced on this page. Can only be passed in as environment variable or hardcoded into home/.chezmoi.yaml.tmpl
CLOUDSDK_CORE_PROJECT Injected into ~/.config/shell/private.sh and saved in your Chezmoi configuration. Can only be passed in as environment variable or hardcoded into home/.chezmoi.yaml.tmpl.
DIGITALOCEAN_ACCESS_TOKEN DigitalOcean personal access token (generated via the Applications & API > Personal access tokens section). Used to connect to DigitalOcean-hosted Kubernetes cluster.
DOCKERHUB_USER DockerHub username which is used in combination with the DOCKERHUB_TOKEN to headlessly authenticate Docker Desktop with DockerHub
DOCKERHUB_TOKEN DockerHub API token stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
ELEVENLABS_API_KEY API key for ElevenLabs which is used by ShortGPT
FIG_TOKEN Fig user API token used to headlessly login / authenticate with Fig. Token can be acquired on the token dashboard after logging in.
FULL_NAME Your full name used in things like the Git config and NPM config. This can be passed in as an environment variable or hardcoded into the home/.chezmoi.yaml.tmpl file.
GCE_SERVICE_ACCOUNT_EMAIL Injected into ~/.config/shell/private.sh and saved in your Chezmoi configuration. Can only be passed in as environment variable or hardcoded into home/.chezmoi.yaml.tmpl.
GITHUB_GIST_TOKEN GitHub token with gist permissions. Populates ~/.local/bin/gist so that the key does not have to be stored in the ~ directory.
GITHUB_READ_TOKEN GitHub token with repository read permissions. Populates ~/.config/ghorg/conf.yaml so Ghorg can backup all of your GitHub repositories locally.
GITHUB_TOKEN GitHub personal access token stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
GITLAB_READ_TOKEN GitLab token with repository read permissions. Populates ~/.config/ghorg/conf.yaml so Ghorg can backup all of your GitLab repositories locally.
GITLAB_TOKEN GitLab personal access token stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
GMAIL_PASSWORD App password for GMail which is used as an outgoing SMTP service (for git e-mail).
GOOGLE_SEARCH_API_KEY API key used by search-gpt available here.
GOOGLE_SEARCH_ID Search engine ID for custom Google search engine utilized by search-gpt available here.
HEADLESS_INSTALL Set to true if you would like all prompts to be bypassed. This variable can only be passed in as an environment variable.
HEROKU_API_KEY Heroku API token stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
HISHTORY_USER_SECRET User secret for synchronizing entries cataloged by Hishtory.
HOARD_API_TOKEN The API token for [Hoard]https://github.com/Hyde46/hoard).
HOST The hostname of the device. Used for a FQDN that resolves to the device when combined with the _ PUBLIC_SERVICES_DOMAIN.
JUMPCLOUD_CONNECT_KEY JumpCloud device enrollment key.
KEYID Your GPG key ID available on the MIT or Ubuntu servers. During provisioning, the key will be imported and trusted with an elevated trust level. This can only be passed in as an environment variable or be hardcoded into the home/.chezmoi.yaml.tmpl file.
NETDATA_ROOM Netdata Cloud room ID to assign the device to. Requires NETDATA_TOKEN to also be defined.
NETDATA_TOKEN Netdata Cloud API token to use when enrolling. Requires NETDATA_ROOM to also be defined.
NGINX_AMPLIFY_API_KEY If NGINX is installed on the system, then this key will be used to join the NGINX Amplify cloud service.
NGROK_AUTH_TOKEN Populates Ngrok token in ~/.config/ngrok/ngrok.yml which allows you to use logged-in-only Ngrok services
NO_RESTART Prevents computer from automatically restarting. This may interfere with system updates.
NPM_TOKEN NPM API token stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
OPENAI_API_KEY OpenAI API key available in the OpenAPI account settings manager. Used for OpenCommit (CLI that automatically generates commit messages).
OVPN_PASSWORD The OpenVPN password to apply to VPN profiles located at ~/.config/vpn/*.ovpn (e.g. encrypted ProtonVPN OpenVPN profiles). OVPN_USERNAME must also be defined.
OVPN_USERNAME The OpenVPN username to apply to VPN profiles located at ~/.config/vpn/*.ovpn (e.g. encrypted ProtonVPN OpenVPN profiles). OVPN_PASSWORD must also be defined.
OPENWEATHERMAP_API_KEY Free API key retrieved from OpenWeatherMap which powers the wego terminal weather application
PORTAINER_BUSINESS_LICENSE Portainer business license key (free for up to 5 nodes)
PRIMARY_EMAIL Your primary e-mail address used in things like the Git config and NPM config. You must pass this as an environment variable or hardcode it into the home/.chezmoi.yaml.tmpl file.
PUBLIC_SERVICES_DOMAIN The CloudFlare domain that you would like to use for CloudFlare DNS integration features. Can only be passed in as an environment variable.
PYPI_TOKEN PyPi.org API token stored in ~/.config/shell/private.sh
REPLICATE_API_KEY Replicate API key (used for AgentGPT)
RESTRICTED_ENVIRONMENT Set to true if you are setting up a device that should not use sudo / administrator privileges. This can only be specified as an environment variable. This feature is a WIP. Pull requests welcome.
SAMBA_NETBIOS_NAME NetBIOS name to use with Samba. Default value is the same value as the HOSTNAME variable. Can only be specified as an environment variable.
SAMBA_WORKGROUP Samba workgroup name. Default value is BETELGEUSE. Can only be specified as an environment variable.
SENDGRID_API_KEY SendGrid API token with the "Mail" permission. Used for sending mail with Postfix.
SERP_API_KEY API key for Serper.dev (used by AgentGPT)
SFTPGO_DEFAULT_ADMIN_PASSWORD Password for default admin user that can login to the SFTPGo web interface.
SFTPGO_DEFAULT_ADMIN_USERNAME Username for default admin user that can login to the SFTPGo web interface.
SLACK_API_TOKEN Slack API personal access token that populates ~/.config/slack-term/config so that you can use Slack from your terminal with slack-term.
SNAPCRAFT_EMAIL Snapcraft.io e-mail address associated with the SNAPCRAFT_MACAROON and SNAPCRAFT_UNBOUND_DISCHARGE (detailed below). Stored in ~/.config/shell/private.sh so developer API credentials can be loaded by running source "~/.config/shell/private.sh". *Can only be included as an environment variable or hardcoded into home/.chezmoi.yaml.tmpl.
SNAPCRAFT_MACAROON Snapcraft.io authentication variable stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
SNAPCRAFT_UNBOUND_DISCHARGE Snapcraft.io authentication variable stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
SOFTWARE_GROUP Should be equal to only of the software lists defined in home/.chezmoidata.yaml (see the Customization page for more details).
START_REPO Set to your GitHub username (if your fork is named install.doctor) to be able to provision your device with the one-liner outlined on the homepage. You can also specify any GitHub project by setting this equal to GITHUB_USERNAME/PROJECT_NAME or a full git address (e.g. git@gitlab.com:megabyte-labs/install.doctor). This can only be passed in as an environment variable.
SUDO_PASSWORD Provide the sudo / administrator password to completely automate sudo password input. This is required on for automated deployments where the user running the script has a sudo password.
SURGE_LOGIN The e-mail address associated with your surge.sh account.
SURGE_TOKEN The surge.sh authentication token acquired by logging in and running surge token.
TIMEZONE Your timezone in the America/New_York format. It should be available in the TZ database. If not passed in as an environment variable, then the device's current timezone will be assumed to be correct.
VAGRANT_CLOUD_TOKEN VagrantUp API token stored in ~/.config/shell/private.sh so developer API keys can be loaded by running source "~/.config/shell/private.sh".
VMWARE_WORKSTATION_LICENSE_KEY License key used for pre-registering VMWare Pro or VMWare Fusion
VNC_PASSWORD VNC password used by macOS VNC system utility or TigerVNC on Linux. Default if not passed in is vncpass.
VNC_READ_PASSWORD VNC password used for a read-only session. Default if not passed in is readonly.
WAKATIME_API_KEY API key for the Wakatime VSCode time tracking plugin which gets injected into ~/.config/wakatime/.wakatime.cfg
WAZUH_MANAGER Address of the Wazuh server to configure the Wazuh client to send data to. Defaults to wazuh.{{ PUBLIC_SERVICES_DOMAIN }}
WINDOWS_11_PRO_KEY Activation key for Windows 11 Professional
WORK_ENVIRONMENT Set to true if you are setting up a corporate device. When true, the provisioning process will avoid installing / configuring things like Tor, which are likely to be banned by corporate networks. This can only be specified as an environment variable. This feature is a WIP. Pull requests welcome.

*Note: When creating a pull request that introduces new variables, please also open a pull request updating this table to reflect those changes. Include a short description of where and how the variable / secret is used in the description column.

SSH Keys

SSH keys can be saved into your fork by encrypting your files and storing them into the home/.chezmoitemplates/ssh/ folder. During the provisioning process, all of the files in the home/.chezmoitemplates/ssh/ folder are decrypted and placed into your ~/.ssh folder. For example, if you wanted to encrypt your current id_rsa file into your fork of Install Doctor, you would run:

chezmoi encrypt "$HOME/id_rsa" > "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/ssh/id_rsa"

After that, your id_rsa file will be encrypted in your fork and you can safely git commit / git push your encrypted id_rsa file to your public GitHub fork.

VPN Profiles

VPN profiles can be stored in encrypted format into your fork by placing *.ovpn, *.conf (WireGuard for macOS), and *.nmconnection (WireGuard for Linux) files into the home/dot_config/vpn/ folder. Before committing the encrypted configurations into your source, you should encrypt the files with chezmoi encrypt and then add the following Go template logic to make sure that the files are only decrypted when the decryption key is present:

{{- if (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) -}}
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAraUZ1dkFITlJMbmdhbXUx
ekQ2SjRhaE5uT3J1czh0V09hSkZuanYvUTJvCklTcHZ6RFBrUGx0VlhqQytEb01a
...
-----END AGE ENCRYPTED FILE-----
{{- end -}}

You also have to make sure that the file names are named exactly how you want the profiles to show up in the operating system UI and also:

  1. Add private_ to the beginning of the file name so that only your user can read the configurations
  2. Add .tmpl to the end of the file name so that the Go template bindings referenced above are handled properly

OVPN Example

The following is an example of the original .ovpn file that is encrypted and stored in home/dot_config/vpn/:

client
dev tun
proto tcp

remote 1xx.1xx.1xx.1xx 8443
remote 1xx.1xx.1xx.1xx 7770
remote 1xx.1xx.1xx.1xx 443

remote-random
resolv-retry infinite
nobind

# The following setting is only needed for old OpenVPN clients compatibility. New clients
# automatically negotiate the optimal cipher.
cipher AES-256-CBC

auth SHA512
verb 3

setenv CLIENT_CERT 0
tun-mtu 1500
tun-mtu-extra 32
mssfix 1450
persist-key
persist-tun

reneg-sec 0

remote-cert-tls server
auth-user-pass
pull
fast-io

script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf

<ca>
-----BEGIN CERTIFICATE-----
MIIFozCCA4ugAwIBAgIBATANBgkqhkiG9w0BAQ0FADBAMxxxxxxxxxxxxxxxxxxx
DK/yPwECUcPgHIeXiRjHnJt0Zcm23O2Q3RphpU+1SO3Xixxxxxxxxxxxxxxxxxxx
A1gTTlpi7A==
-----END CERTIFICATE-----
</ca>

key-direction 1
<tls-auth>
# 2048 bit OpenVPN static key
-----BEGIN OpenVPN Static key V1-----
6acef03f62675b4b1bbd0xxxxxxxxxxx
...
16672ea16c012664f8a9fxxxxxxxxxxx
-----END OpenVPN Static key V1-----
</tls-auth>

After the .ovpn file is decrypted to ~/.config/vpn/ during the provision process, if the OVPN_PASSWORD and OVPN_USERNAME are defined (as either environment variables or secrets stored at home/.chezmoitemplates/secrets/), then the file will be properly loaded into the NetworkManager on Linux and equivalent programs on macOS / Windows.

It is important to note that we only support passing one set of OVPN_PASSWORD and OVPN_USERNAME to the provision process so if you have OpenVPN connections from multiple providers with different usernames and passwords then you will have to extend our default logic.

WireGuard Example

The following is an example of a decrypted .nmconnection file stored in home/dot_config/vpn/:

[connection]
id=Proton WG Cambodia (UDP 51820)
uuid=2xxxxxx-30xx-xxxx-xxxx-85xxxxxxxxxx
type=vpn
autoconnect=true
permissions=user:xxx:;

[vpn]
connection-dns=10.2.0.1
local-ip4=10.2.0.2/32
local-private-key=oKHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
peer-allowed-ips=0.0.0.0/0
peer-endpoint=185.159.156.83:51820
peer-public-key=D4M0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
service-type=org.freedesktop.NetworkManager.wireguard

[ipv4]
dns-search=
method=auto

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
method=auto

[proxy]

As you can see, the authentication keys are located directly in the file so there is no need to load a username and password like in the case of the OpenVPN profiles. The .nmconnection files are specific to the NetworkManager on Linux systems. You may have to craft the .nmconnection files by loading your configuration into the NetworkManager program and then grabbing the source from the resulting .nmconnection file.

On macOS / Windows, the WireGuard .conf file format is used. The same .nmconnection file above would look like this in .conf format:

[Interface]
# NetShield = 1
# Moderate NAT = off
# VPN Accelerator = on
PrivateKey = oKHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
Address = 10.2.0.2/32
DNS = 10.2.0.1

[Peer]
# SE-KH#1
PublicKey = D4M0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
AllowedIPs = 0.0.0.0/0
Endpoint = 185.159.156.83:51820

Encrypted Files

There are a few cases where entire files need to be encrypted. Whenever possible, in cases like Tabby's configuration stored at home/dot_config/tabby/config.yaml.tmpl the optimized configuration stripped of secrets is provided as a fallback within the template. In cases like this, where no environment variable configuration parameter is made available, the encrypted file parts are stored in home/.chezmoitemplates/files/. The table below describes the capabilities that are offered by these files:

File in .chezmoitemplates/files/ Description
tabby The Tabby configuration file which can include several types of encryption keys in it. Used in home/dot_config/tabby/config.yaml.tmpl.
google-assistant-client-secret The client secret required for the unofficial Google Assistant desktop applications. Details on how to set it can be found on the project's wiki. Used in home/dot_config/Google Assistant/client-secret.json.tmpl. The google-assistant-tokens file is also required (details below).
google-assistant-tokens The tokens required for setting up the unofficial Google Assistant. Used in home/dot_config/Google Assistant/tokens.json.tmpl. The google-assistant-client-secret is also required (details above)
gphotos-sync The Google Photos API client secret file required for using gphotos-sync to backup your Google Photos content. Used in home/dot_config/gphotos-sync/client_secret.json.tmpl.

If you inspect the files above, you will see that they are stored in their target location as a template that first checks if the encryption key is present. If the key is present, the files get decrypted. Ideally, if the key is not present, then a version of the file without sensitive information should be rendered. An example of this can be found in the Tabby configuration (home/dot_config/tabby/config.yaml). When contributing to this project, be sure to include this fallback logic whenever possible so that users who have not populated their fork with encrypted secrets can still retain functionality.

Creating New Variables / Secrets

If you want to expand the capabilities of your fork beyond what we have provided, we recommend you follow the same approach we use when handling environment variables and secret encrypted keys.

Combining Variables and Secrets

Ideally, whenever possible, the user should be able to pass in a variable as either an environment variable or as a secret included in the fork. In the ~/.config/shell/private.sh file which houses private keys for cloud APIs that the user may want to source by running . "~/.config/shell/private.sh", the DockerHub token is defined with:

export DOCKERHUB_TOKEN="{{ if (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "key-DOCKERHUB_TOKEN")) }}{{ includeTemplate "secrets/key-DOCKERHUB_TOKEN" }}{{ else }}{{ env "DOCKERHUB_TOKEN" }}{{ end }}"
export DOCKERHUB_REGISTRY_PASSWORD="$DOCKERHUB_TOKEN"

This approach works well because it first checks for the presence of the home/.chezmoitemplates/secrets/key-DOCKERHUB_TOKEN file and then decrypts the value and injects it into the results private.sh file if the key-DOCKERHUB_TOKEN is present. Otherwise, it attempts to use the DOCKERHUB_TOKEN key.

Note: Preferrably, you should store the secret as the same name as the corresponding environment variable. That is, an environment variable named DOCKERHUB_TOKEN should be stored as a key stored in home/.chezmoitemplates/secrets/key-DOCKERHUB_TOKEN. Additionally, encrypted files that decrypt to files stored in ~/.ssh/ should be prefixed with ssh- instead of key-.

Encrypted Files

For encrypted files, you should mark the file as a templated file by ending the file name with .tmpl and then you should include a check to make sure both the decryption key and the encrypted secret data location is available. For example, our ~/.ssh/id_rsa file is generated by placing a file in home/private_dot_ssh/private_id_rsa.tmpl with the following content that makes these checks:

{{- if and (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "ssh-id-rsa")) -}}
{{   includeTemplate "secrets/ssh-id-rsa" | decrypt -}}
{{ end -}}

At provisioning time, if the necessary files are available, the encrypted secret data stored in home/.chezmoitemplates/secrets/ssh-id-rsa will be decrypted and added to the ~/.ssh/id_rsa file.