<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Security on Backend Engineering Strategy Tools</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/</link><description>Recent content in Security on Backend Engineering Strategy Tools</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 01 Jan 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://backend-engineering-strategy-tools.github.io/site/public-notes/security/index.xml" rel="self" type="application/rss+xml"/><item><title>Linux Identity Management — FreeIPA and SSSD</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/linux-identity/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/linux-identity/</guid><description>&lt;p&gt;Managing user accounts across many Linux machines by hand — creating the same user on every host, syncing passwords, maintaining sudo rules — breaks down fast. FreeIPA provides centralised identity management: one place to define users, groups, sudo rules, host policies, and SSH keys. SSSD is the daemon that runs on each Linux machine and connects it to FreeIPA (or any LDAP/Kerberos provider), making those central definitions available locally.&lt;/p&gt;
&lt;h2 id="freeipa"&gt;FreeIPA
&lt;/h2&gt;&lt;p&gt;An integrated identity management solution from Red Hat, combining LDAP (389 Directory Server), Kerberos, DNS, a certificate authority, and a web UI into a single deployable stack. Users, groups, sudo rules, HBAC (host-based access control) rules, and SSH public keys are all managed centrally and enforced on enrolled hosts. FreeIPA is the open source upstream of Red Hat Identity Management (IdM).&lt;/p&gt;
&lt;p&gt;Install on RHEL/Rocky/AlmaLinux:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dnf install freeipa-server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ipa-server-install --domain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;example.com --realm&lt;span style="color:#f92672"&gt;=&lt;/span&gt;EXAMPLE.COM
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the server is running, enroll a client host:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dnf install freeipa-client
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ipa-client-install --server&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ipa.example.com --domain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;example.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After enrollment, users defined in FreeIPA can log into the host with Kerberos SSO — no separate account needed on the machine.&lt;/p&gt;
&lt;h2 id="sssd"&gt;SSSD
&lt;/h2&gt;&lt;p&gt;The System Security Services Daemon. SSSD runs on each Linux host and mediates all identity lookups — NSS (name service switch) queries for users and groups, PAM authentication, sudo rule lookups. It caches responses locally so logins still work when the identity server is temporarily unreachable, and it handles the Kerberos ticket lifecycle transparently.&lt;/p&gt;
&lt;p&gt;SSSD is not FreeIPA-specific. It supports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FreeIPA (the natural pairing)&lt;/li&gt;
&lt;li&gt;Active Directory (via the &lt;code&gt;ad&lt;/code&gt; provider — direct AD integration without Samba)&lt;/li&gt;
&lt;li&gt;Generic LDAP and Kerberos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;ipa-client-install&lt;/code&gt; command configures SSSD automatically when enrolling a FreeIPA client. For AD integration, the configuration is similar but uses the &lt;code&gt;ad&lt;/code&gt; provider:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[domain/example.com]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;id_provider&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;ad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;auth_provider&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;ad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;access_provider&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;ad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ad_domain&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;example.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;krb5_realm&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;EXAMPLE.COM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="the-pairing"&gt;The pairing
&lt;/h2&gt;&lt;p&gt;FreeIPA and SSSD are complementary halves of the same solution. FreeIPA is the authoritative store — where you create and manage identities. SSSD is the enforcer on each host — it translates FreeIPA&amp;rsquo;s policies into local authentication decisions, caches them for resilience, and keeps Kerberos tickets current. Neither replaces the other; together they give you centralised identity management with no single point of failure for login availability.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.freeipa.org/page/Documentation" target="_blank" rel="noopener"
 &gt;FreeIPA documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://sssd.io/docs/" target="_blank" rel="noopener"
 &gt;SSSD documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/managing_idm_users_groups_hosts_and_access_control_rules/" target="_blank" rel="noopener"
 &gt;Red Hat IdM documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>LUKS — Linux Disk Encryption</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/luks/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/luks/</guid><description>&lt;p&gt;LUKS (Linux Unified Key Setup) is the standard for full-disk encryption on Linux. It uses dm-crypt in the kernel to encrypt block devices transparently — the filesystem sits on top of an encrypted layer, and the encryption happens below it. The LUKS header stores the encrypted key material and metadata, supporting up to eight independent key slots (passphrases or keyfiles) that all unlock the same volume.&lt;/p&gt;
&lt;h2 id="setup"&gt;Setup
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Encrypt a device (destroys existing data)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cryptsetup luksFormat /dev/sdb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Open the encrypted device, exposing it as a plaintext mapper device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cryptsetup luksOpen /dev/sdb data-encrypted
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Format and use the plaintext device normally&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkfs.ext4 /dev/mapper/data-encrypted
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mount /dev/mapper/data-encrypted /mnt/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Close when done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;umount /mnt/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cryptsetup luksClose data-encrypted
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="key-slots"&gt;Key slots
&lt;/h2&gt;&lt;p&gt;LUKS supports multiple passphrases or keyfiles — useful for adding a recovery key alongside an operational passphrase:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Add a second key slot (e.g. a recovery keyfile)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cryptsetup luksAddKey /dev/sdb /path/to/recovery.key
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Remove a key slot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cryptsetup luksRemoveKey /dev/sdb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# List key slot usage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cryptsetup luksDump /dev/sdb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="auto-unlock-at-boot"&gt;Auto-unlock at boot
&lt;/h2&gt;&lt;p&gt;For encrypted root or data partitions that should unlock automatically on boot, add the device to &lt;code&gt;/etc/crypttab&lt;/code&gt; with a keyfile path:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;data-encrypted /dev/sdb /etc/keys/data.key luks
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then add the plaintext device to &lt;code&gt;/etc/fstab&lt;/code&gt; as normal. On servers, the keyfile is stored on a separate volume or fetched from a secrets manager (Vault, Tang/Clevis for network-bound disk encryption).&lt;/p&gt;
&lt;h2 id="use-in-kubernetes"&gt;Use in Kubernetes
&lt;/h2&gt;&lt;p&gt;Node-level disk encryption with LUKS protects data at rest on Kubernetes worker nodes — persistent volume data stored on the node&amp;rsquo;s disks is encrypted before it leaves the kernel. Talos Linux enables LUKS encryption for its state and ephemeral partitions by default.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://gitlab.com/cryptsetup/cryptsetup/-/wikis/home" target="_blank" rel="noopener"
 &gt;cryptsetup documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://wiki.archlinux.org/title/dm-crypt" target="_blank" rel="noopener"
 &gt;dm-crypt reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Security Scanning &amp; Monitoring</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/security-scanning/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/security-scanning/</guid><description>&lt;p&gt;Security tooling broadly splits into three concerns: what vulnerabilities exist in your software before it runs (image scanning), what is actually happening on your systems while they run (endpoint monitoring), and what is moving across your network (intrusion detection). Clair, osquery, and SNORT each cover one of these.&lt;/p&gt;
&lt;h2 id="clair"&gt;Clair
&lt;/h2&gt;&lt;p&gt;A static analysis tool for container image vulnerability scanning, from the Quay project (Red Hat). Clair maintains a database of CVEs from multiple sources (NVD, Red Hat, Debian, Alpine, Ubuntu) and matches them against the packages installed in a container image layer by layer. Integrated into a container registry, it scans every image on push and blocks or flags images with known vulnerabilities above a configurable severity threshold. The result is a vulnerability report tied to the image digest — not the running container, but the image itself before it&amp;rsquo;s ever deployed.&lt;/p&gt;
&lt;h2 id="osquery"&gt;osquery
&lt;/h2&gt;&lt;p&gt;Facebook&amp;rsquo;s open source endpoint monitoring tool. osquery exposes the operating system as a relational database — processes, users, network connections, installed packages, kernel modules, scheduled tasks, browser extensions — all queryable with SQL. This makes ad-hoc security investigation fast (a single query answers &amp;ldquo;which processes are listening on unexpected ports?&amp;rdquo;) and continuous monitoring straightforward (schedule queries, collect results centrally, alert on anomalies). osquery runs on Linux, macOS, and Windows. Used standalone it is a powerful investigation tool; integrated with a SIEM or fleet management layer (Fleet, Kolide) it becomes a continuous compliance and detection platform.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Processes with open network connections
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; p.name, p.pid, l.address, l.port
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; processes p
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;JOIN&lt;/span&gt; listening_ports l &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; p.pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; l.pid
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; l.port &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;IN&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;443&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="snort"&gt;SNORT
&lt;/h2&gt;&lt;p&gt;A network intrusion detection and prevention system (IDS/IPS). SNORT inspects network traffic in real time against a ruleset — signatures for known attack patterns, protocol anomalies, port scans, exploit attempts. In IDS mode it logs and alerts; in IPS mode it can drop matching packets inline. SNORT rules are expressive and the community ruleset (Snort Community Rules, Emerging Threats) covers a wide range of threats. Placed at a network chokepoint — in front of a server, at the edge of a network segment — it gives visibility into what traffic is actually reaching your systems and can detect lateral movement, exfiltration attempts, and known exploits in transit.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://quay.github.io/clair/" target="_blank" rel="noopener"
 &gt;Clair documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://osquery.readthedocs.io/" target="_blank" rel="noopener"
 &gt;osquery documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.snort.org/documents" target="_blank" rel="noopener"
 &gt;SNORT documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://rules.emergingthreats.net/" target="_blank" rel="noopener"
 &gt;Emerging Threats ruleset&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>SSH</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/</guid><description>&lt;p&gt;SSH (Secure Shell) is the standard protocol for encrypted remote access to Linux and Unix systems. It replaced telnet and rsh by wrapping the session in a cryptographic tunnel — authentication, commands, and data transfer all protected against interception and tampering.&lt;/p&gt;
&lt;h2 id="public-key-authentication"&gt;Public key authentication
&lt;/h2&gt;&lt;p&gt;The default auth mechanism for any serious setup. You generate a key pair: a private key that never leaves your machine, and a public key that goes on the remote host.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ssh-keygen -t ed25519 -C &lt;span style="color:#e6db74"&gt;&amp;#34;your@email.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ssh-copy-id user@host &lt;span style="color:#75715e"&gt;# appends public key to ~/.ssh/authorized_keys on remote&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Prefer &lt;code&gt;ed25519&lt;/code&gt; over the older &lt;code&gt;rsa&lt;/code&gt; — smaller keys, faster, stronger. Keep your private key protected with a passphrase; use &lt;code&gt;ssh-agent&lt;/code&gt; to avoid typing it repeatedly.&lt;/p&gt;
&lt;h2 id="key-deployment-at-scale"&gt;Key deployment at scale
&lt;/h2&gt;&lt;p&gt;When you have many hosts, distributing public keys manually doesn&amp;rsquo;t scale. A typical pattern: submit your public key to a central approval system, which then deploys it to the relevant hosts via automation (Ansible, Puppet, etc.).&lt;/p&gt;
&lt;p&gt;&lt;img alt="SSH key deployment flow" class="gallery-image" data-flex-basis="480px" data-flex-grow="200" height="1280" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/ssh-deploy-rgm.png" srcset="https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/ssh-deploy-rgm_hu_7067fdd6ddfbd76d.png 800w, https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/ssh-deploy-rgm_hu_a732934bde95612.png 1600w, https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/ssh-deploy-rgm_hu_4339d3dc0eb426e1.png 2400w, https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/ssh-deploy-rgm.png 2560w" width="2560"&gt;&lt;/p&gt;
&lt;p&gt;This keeps a clear audit trail — keys are approved, recorded, and can be revoked centrally without touching individual &lt;code&gt;authorized_keys&lt;/code&gt; files.&lt;/p&gt;
&lt;h2 id="certificate-authentication"&gt;Certificate authentication
&lt;/h2&gt;&lt;p&gt;At larger scale, even centralised key distribution gets unwieldy. SSH certificates solve this properly: instead of deploying individual public keys, you run an SSH Certificate Authority (CA). Hosts and users trust the CA, not each other&amp;rsquo;s individual keys.&lt;/p&gt;
&lt;p&gt;&lt;img alt="SSH certificate authentication architecture" class="gallery-image" data-flex-basis="528px" data-flex-grow="220" height="1018" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/ssh-certificate-authentication.png" srcset="https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/ssh-certificate-authentication_hu_3c89cbd02831450b.png 800w, https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/ssh-certificate-authentication_hu_98e8f600ea8421b2.png 1600w, https://backend-engineering-strategy-tools.github.io/site/public-notes/security/ssh/ssh-certificate-authentication.png 2242w" width="2242"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generate a key pair locally&lt;/li&gt;
&lt;li&gt;Submit the public key to the SSH CA (backed by your identity provider — FreeIPA, Vault, etc.)&lt;/li&gt;
&lt;li&gt;The CA issues a signed certificate with a short TTL&lt;/li&gt;
&lt;li&gt;SSH to any host — the host trusts the CA, so the certificate is accepted without any pre-deployed keys&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Short-lived certificates (hours, not days) dramatically reduce the blast radius of a compromised credential. No revocation lists to maintain.&lt;/p&gt;
&lt;h2 id="ssh-config"&gt;SSH config
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;~/.ssh/config&lt;/code&gt; avoids repetitive flags on every connection:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Host bastion
 HostName bastion.example.com
 User deploy
 IdentityFile ~/.ssh/id_ed25519
 ForwardAgent yes

Host internal-*
 ProxyJump bastion
 User deploy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ProxyJump&lt;/code&gt; (formerly &lt;code&gt;-J&lt;/code&gt;) lets you reach hosts that aren&amp;rsquo;t directly accessible — you SSH through the bastion transparently.&lt;/p&gt;
&lt;h2 id="port-forwarding"&gt;Port forwarding
&lt;/h2&gt;&lt;p&gt;SSH can tunnel TCP traffic, useful for reaching services on private networks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Local forward: reach remote Postgres via localhost:5432&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ssh -L 5432:db.internal:5432 bastion
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Dynamic forward: SOCKS proxy through the bastion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ssh -D &lt;span style="color:#ae81ff"&gt;1080&lt;/span&gt; bastion
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="hardening-basics"&gt;Hardening basics
&lt;/h2&gt;&lt;p&gt;Key settings in &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers deploy ansible
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Disable password auth entirely once keys are in place. Restrict which users can log in. Run &lt;code&gt;sshd -t&lt;/code&gt; to validate config before reloading.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.openssh.com/manual.html" target="_blank" rel="noopener"
 &gt;OpenSSH manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://developer.hashicorp.com/vault/docs/secrets/ssh/signed-ssh-certificates" target="_blank" rel="noopener"
 &gt;SSH certificate authentication (HashiCorp Vault)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://infosec.mozilla.org/guidelines/openssh" target="_blank" rel="noopener"
 &gt;Mozilla SSH Guidelines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>TLS Certificates — Let's Encrypt, Certbot, cert-manager</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/tls-certificates/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/security/tls-certificates/</guid><description>&lt;p&gt;TLS certificates prove that a server is who it claims to be and encrypt traffic in transit. Getting and renewing them used to mean manual requests to a CA, waiting days, and calendar reminders to renew before expiry. Let&amp;rsquo;s Encrypt automated the entire process in 2015 and made it free. Today there is no reason to run a public service without TLS.&lt;/p&gt;
&lt;h2 id="lets-encrypt"&gt;Let&amp;rsquo;s Encrypt
&lt;/h2&gt;&lt;p&gt;A free, automated, open certificate authority run by the Internet Security Research Group. Let&amp;rsquo;s Encrypt issues Domain Validation (DV) certificates valid for 90 days, automatically, via the ACME protocol. The short lifetime is intentional — it forces automation and limits the window if a certificate is compromised. Let&amp;rsquo;s Encrypt is now the largest CA in the world by certificates issued. You never interact with Let&amp;rsquo;s Encrypt directly; you use an ACME client that speaks the protocol on your behalf.&lt;/p&gt;
&lt;h2 id="certbot"&gt;Certbot
&lt;/h2&gt;&lt;p&gt;The EFF&amp;rsquo;s ACME client — the most widely used way to obtain and renew Let&amp;rsquo;s Encrypt certificates on a Linux server. Certbot handles the ACME challenge (proving you control the domain), fetches the certificate, installs it into your web server config (nginx, Apache), and sets up a cron job or systemd timer for automatic renewal. For a straightforward public-facing server, Certbot is the default choice:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot --nginx -d example.com -d www.example.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Certbot supports HTTP-01 challenges (serve a file over port 80) and DNS-01 challenges (add a TXT record — required for wildcard certificates and useful when port 80 isn&amp;rsquo;t accessible).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Wildcard cert via DNS challenge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot certonly --manual --preferred-challenges dns -d &lt;span style="color:#e6db74"&gt;&amp;#34;*.example.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Renewals run automatically. Check the timer is active:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl status certbot.timer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="cert-manager"&gt;cert-manager
&lt;/h2&gt;&lt;p&gt;The Kubernetes-native way to manage certificates. cert-manager runs as a controller in the cluster and automates the full certificate lifecycle — requesting, renewing, and storing certificates as Kubernetes &lt;code&gt;Secret&lt;/code&gt; resources. It supports Let&amp;rsquo;s Encrypt via ACME (HTTP-01 and DNS-01 challenges) as well as other issuers (Vault, Venafi, self-signed).&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;ClusterIssuer&lt;/code&gt; configures the CA once for the whole cluster:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ClusterIssuer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt-prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;acme&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;server&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://acme-v02.api.letsencrypt.org/directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;email&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;admin@example.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;privateKeySecretRef&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt-prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;solvers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;http01&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ingress&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;class&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;alb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A &lt;code&gt;Certificate&lt;/code&gt; resource then requests a cert for a specific domain — or an Ingress annotation triggers cert-manager automatically. The certificate is stored as a Secret and mounted into pods or referenced by the Ingress. Renewal happens automatically before expiry.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://letsencrypt.org/docs/" target="_blank" rel="noopener"
 &gt;Let&amp;rsquo;s Encrypt documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://certbot.eff.org/docs/" target="_blank" rel="noopener"
 &gt;Certbot documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://cert-manager.io/docs/" target="_blank" rel="noopener"
 &gt;cert-manager documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>