<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>natkit</title><link>https://natkit.ulm0.com/</link><description>Recent content on natkit</description><generator>Hugo</generator><language>en</language><atom:link href="https://natkit.ulm0.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Getting started</title><link>https://natkit.ulm0.com/docs/getting-started/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/getting-started/</guid><description>&lt;p&gt;natkit is a NAT instance AMI for AWS, built for arm64 and x86_64. It has &lt;a href="https://github.com/AndrewGuenther/fck-nat" rel="external" target="_blank"&gt;fck-nat&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&amp;rsquo;s features on &lt;a href="https://github.com/linuxkit/linuxkit" rel="external" target="_blank"&gt;LinuxKit&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; instead of Amazon Linux, systemd and Packer. The OS is an immutable in-memory image:&lt;/p&gt;</description></item><item><title>Configuration</title><link>https://natkit.ulm0.com/docs/configuration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/configuration/</guid><description>&lt;p&gt;natkit reads its settings from YAML user-data, with the same keys as fck-nat&amp;rsquo;s &lt;code&gt;/etc/fck-nat.conf&lt;/code&gt;. Every key is optional: with none at all, natkit is a plain NAT out of the primary ENI.&lt;/p&gt;&#10;&#10;&#10;&#10; &#10; &#10; &#10;&#10; &#10; &#10; &#10; &#10;&#10; &#10;&#10; &lt;div class="prism-codeblock "&gt;&#10; &lt;pre id="8c2c4d0" class="language-yaml "&gt;&#10; &lt;code&gt;eip_id: eipalloc-0123 # associate this EIP with the primary ENI (after eni_id&amp;#39;s ENI is attached)&#10;eni_id: eni-0123 # HA: attach this static ENI (the route tables&amp;#39; target) as device 1,&#10; # turn off the primary ENI&amp;#39;s source/dest check&#10;interface: eth0 # public interface, if not the primary ENI&amp;#39;s (ignored with eni_id)&#10;nat64: false # no NAT64 (default: on)&#10;ip_local_port_range: &amp;#34;1024 65535&amp;#34; # tuning, applied only when set&#10;nf_conntrack_max: 262144&#10;nf_conntrack_buckets: 65536&#10;nf_conntrack_tcp_timeout_established: 86400&#10;tcp_keepalive_time: 600&#10;tcp_max_syn_backlog: 4096&#10;cwagent_enabled: true # CloudWatch agent with the JSON config in this SSM parameter&#10;cwagent_cfg_param_name: /natkit/cwagent&#10;console_password: /natkit/root-hash # SSM parameter holding `openssl passwd -6` output: serial console login&lt;/code&gt;&#10; &lt;/pre&gt;&#10; &lt;/div&gt;&#10;&lt;p&gt;An unknown key or a malformed value stops the setup. The console then prints &lt;code&gt;natkit: FAIL &amp;lt;reason&amp;gt;&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>High availability</title><link>https://natkit.ulm0.com/docs/high-availability/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/high-availability/</guid><description>&lt;p&gt;For HA, run natkit in an Auto Scaling group of one, with &lt;code&gt;eni_id&lt;/code&gt; and &lt;code&gt;eip_id&lt;/code&gt; in its user-data:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Static ENI (&lt;code&gt;eni_id&lt;/code&gt;):&lt;/strong&gt; the private route tables point at this ENI, not at an instance. The instance attaches it as device 1.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;EIP (&lt;code&gt;eip_id&lt;/code&gt;):&lt;/strong&gt; the instance associates it with its primary ENI, so egress keeps the same public IP across replacements.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;When an instance is replaced:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;The new instance keeps retrying the ENI attachment while the old one still holds it, for up to 15 minutes.&lt;/li&gt;&#10;&lt;li&gt;Once it has the ENI, it takes the EIP.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;fck-nat takes the EIP first. That moves egress off the EIP while the old instance is still routing. natkit waits for the ENI first to avoid that gap.&lt;/p&gt;</description></item><item><title>NAT64</title><link>https://natkit.ulm0.com/docs/nat64/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/nat64/</guid><description>&lt;p&gt;NAT64 is on unless the user-data sets &lt;code&gt;nat64: false&lt;/code&gt;. &lt;a href="https://nicmx.github.io/Jool/" rel="external" target="_blank"&gt;Jool&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; translates &lt;code&gt;64:ff9b::/96&lt;/code&gt; to IPv4.&lt;/p&gt;&#10;&lt;p&gt;To use it:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;turn on Route 53 Resolver DNS64 on the IPv6 subnets;&lt;/li&gt;&#10;&lt;li&gt;add a &lt;code&gt;64:ff9b::/96&lt;/code&gt; route to the instance;&lt;/li&gt;&#10;&lt;li&gt;give the instance&amp;rsquo;s ENI an IPv6 address.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Jool&amp;rsquo;s default IPv4 pool is ports 61001-65535 of the instance&amp;rsquo;s address. Keep &lt;code&gt;ip_local_port_range&lt;/code&gt; below that.&lt;/p&gt;</description></item><item><title>OpenTofu module</title><link>https://natkit.ulm0.com/docs/opentofu/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/opentofu/</guid><description>&lt;p&gt;&lt;code&gt;tofu/nat&lt;/code&gt; sets up the &lt;a href="../high-availability/"&gt;HA layout&lt;/a&gt; as a module:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;an Auto Scaling group of one;&lt;/li&gt;&#10;&lt;li&gt;a static ENI and an EIP;&lt;/li&gt;&#10;&lt;li&gt;the private route tables&amp;rsquo; routes;&lt;/li&gt;&#10;&lt;li&gt;a scoped instance role.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&#10;&#10; &#10; &#10; &#10;&#10; &#10; &#10; &#10; &#10;&#10; &#10;&#10; &lt;div class="prism-codeblock "&gt;&#10; &lt;pre id="5ff401b" class="language-hcl "&gt;&#10; &lt;code&gt;module &amp;#34;nat&amp;#34; {&#10; source = &amp;#34;github.com/ulm0/natkit//tofu/nat&amp;#34;&#10; vpc_id = aws_vpc.main.id&#10; subnet_id = aws_subnet.public.id&#10; route_table_ids = [aws_route_table.private.id]&#10; ami_id = &amp;#34;ami-...&amp;#34; # natkit-&amp;lt;version&amp;gt;-arm64&#10; instance_type = &amp;#34;t4g.micro&amp;#34;&#10; settings = { nf_conntrack_max = &amp;#34;262144&amp;#34; }&#10;}&lt;/code&gt;&#10; &lt;/pre&gt;&#10; &lt;/div&gt;&#10;&lt;h2 id="inputs"&gt;Inputs &lt;a href="#inputs" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Name&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Default&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;vpc_id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the VPC&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;subnet_id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;public subnet (internet gateway route) for the instance and its static ENI&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;route_table_ids&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;private route tables that get &lt;code&gt;0.0.0.0/0&lt;/code&gt; (and &lt;code&gt;64:ff9b::/96&lt;/code&gt; with &lt;code&gt;nat64&lt;/code&gt;) to the static ENI&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ami_id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a natkit AMI of the instance type&amp;rsquo;s architecture&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;natkit&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;name and &lt;code&gt;natkit&lt;/code&gt; tag of every resource&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;instance_type&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;t4g.micro&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;see &lt;a href="../getting-started/#instance-size"&gt;instance size&lt;/a&gt;: &lt;code&gt;t4g.nano&lt;/code&gt; is not supported&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eip&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;allocate an EIP and have the instance take it. Otherwise it egresses from its own public IP, which changes on replacement&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nat64&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;route &lt;code&gt;64:ff9b::/96&lt;/code&gt; to the ENI and give it an IPv6 address (the subnet needs an IPv6 CIDR)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ipv6_cidr&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the VPC&amp;rsquo;s IPv6 CIDR, admitted by the security group: needed with &lt;code&gt;nat64&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;settings&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;more &lt;a href="../configuration/"&gt;user-data keys&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;cwagent_cfg_param_name&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;SSM parameter with a CloudWatch agent JSON config: enables the agent&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;console_password_param&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;SSM parameter with root&amp;rsquo;s crypt hash for the EC2 Serial Console&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;extra tags&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="outputs"&gt;Outputs &lt;a href="#outputs" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;eni_id&lt;/code&gt;, &lt;code&gt;public_ip&lt;/code&gt; (the EIP, with &lt;code&gt;eip = true&lt;/code&gt;), &lt;code&gt;security_group_id&lt;/code&gt;, &lt;code&gt;role_name&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Instance role</title><link>https://natkit.ulm0.com/docs/instance-role/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/instance-role/</guid><description>&lt;p&gt;natkit only needs an instance role for the keys that call AWS:&lt;/p&gt;&#10;&#10;&#10;&#10; &#10; &#10; &#10;&#10; &#10; &#10; &#10; &#10;&#10; &#10;&#10; &lt;div class="prism-codeblock "&gt;&#10; &lt;pre id="9912192" class="language-json "&gt;&#10; &lt;code&gt;{&#10; &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10; &amp;#34;Statement&amp;#34;: [&#10; {&amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;, &amp;#34;Action&amp;#34;: &amp;#34;ec2:AssociateAddress&amp;#34;, &amp;#34;Resource&amp;#34;: &amp;#34;*&amp;#34;},&#10; {&amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;, &amp;#34;Action&amp;#34;: [&amp;#34;ec2:AttachNetworkInterface&amp;#34;, &amp;#34;ec2:ModifyNetworkInterfaceAttribute&amp;#34;], &amp;#34;Resource&amp;#34;: &amp;#34;*&amp;#34;},&#10; {&amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;, &amp;#34;Action&amp;#34;: &amp;#34;ssm:GetParameter&amp;#34;, &amp;#34;Resource&amp;#34;: &amp;#34;arn:aws:ssm:*:*:parameter/natkit/*&amp;#34;}&#10; ]&#10;}&lt;/code&gt;&#10; &lt;/pre&gt;&#10; &lt;/div&gt;&#10;&lt;p&gt;With &lt;code&gt;cwagent_enabled&lt;/code&gt;, also attach &lt;code&gt;CloudWatchAgentServerPolicy&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;Scope &lt;code&gt;Resource&lt;/code&gt; down to your EIP, ENI and instances where you can. The &lt;a href="../opentofu/"&gt;OpenTofu module&lt;/a&gt;&amp;rsquo;s role does this: tag conditions on the ENIs and instances, and the one EIP and SSM parameters by ARN.&lt;/p&gt;</description></item><item><title>CloudWatch agent</title><link>https://natkit.ulm0.com/docs/cloudwatch/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/cloudwatch/</guid><description>&lt;p&gt;To run the CloudWatch agent, set these user-data keys:&lt;/p&gt;&#10;&#10;&#10;&#10; &#10; &#10; &#10;&#10; &#10; &#10; &#10; &#10;&#10; &#10;&#10; &lt;div class="prism-codeblock "&gt;&#10; &lt;pre id="8f059ca" class="language-yaml "&gt;&#10; &lt;code&gt;cwagent_enabled: true&#10;cwagent_cfg_param_name: /natkit/cwagent # SSM parameter with the agent&amp;#39;s JSON config&lt;/code&gt;&#10; &lt;/pre&gt;&#10; &lt;/div&gt;&#10;&lt;p&gt;The instance role also needs &lt;code&gt;CloudWatchAgentServerPolicy&lt;/code&gt; and &lt;code&gt;ssm:GetParameter&lt;/code&gt; on the parameter.&lt;/p&gt;&#10;&lt;p&gt;The agent image is not in the AMI. natkit pulls it by digest from &lt;code&gt;public.ecr.aws&lt;/code&gt; at boot, only when the agent is enabled, through the NAT&amp;rsquo;s own egress. It is about 150 MB unpacked and stays in memory: use at least a &lt;code&gt;t4g.micro&lt;/code&gt; or &lt;code&gt;t3.micro&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Hardening</title><link>https://natkit.ulm0.com/docs/hardening/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/hardening/</guid><description>&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Login:&lt;/strong&gt; no SSH, SSM agent or package manager. The only login is the EC2 Serial Console. It stays locked unless &lt;code&gt;console_password&lt;/code&gt; is set.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Inbound:&lt;/strong&gt; the instance accepts no new inbound connections to itself. The nftables input policy is drop: replies, ICMP and DHCP only.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Forwarded traffic:&lt;/strong&gt; not filtered (use the security group), except packets conntrack calls invalid, which would otherwise leave un-NATed.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Credentials:&lt;/strong&gt; AWS credentials reach &lt;code&gt;curl&lt;/code&gt; on stdin, never on a command line.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Kernel:&lt;/strong&gt; built from &lt;code&gt;allnoconfig&lt;/code&gt;, with no USB, wireless, filesystems beyond tmpfs/overlay, &lt;code&gt;/dev/mem&lt;/code&gt;, kexec or 32-bit syscalls. CPU mitigations, KASLR, stack protector, hardened usercopy and zeroed allocations are on. Module loading is disabled once Jool is in.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Network stack:&lt;/strong&gt; no ICMP redirects or source routing. Unprivileged BPF and kernel log access are off.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Capabilities:&lt;/strong&gt; &lt;code&gt;natkit-init&lt;/code&gt; runs with three capabilities. The CloudWatch agent launcher runs with &lt;code&gt;CAP_SYS_ADMIN&lt;/code&gt; only: &lt;code&gt;ctr run&lt;/code&gt; mounts the agent image&amp;rsquo;s rootfs, and its containerd socket is root-equivalent anyway.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Supply chain:&lt;/strong&gt; images are pinned by digest or content hash, and the Jool source by checksum. IMDSv2 only.&lt;/li&gt;&#10;&lt;/ul&gt;</description></item><item><title>natkit and fck-nat</title><link>https://natkit.ulm0.com/docs/comparison/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/comparison/</guid><description>&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;fck-nat&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;natkit&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Amazon Linux 2023, systemd unit &lt;code&gt;fck-nat.service&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;LinuxKit &lt;code&gt;onboot&lt;/code&gt; container &lt;code&gt;natkit-init&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/etc/fck-nat.conf&lt;/code&gt; written by a cloud-init script&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;YAML user-data with the same keys&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws&lt;/code&gt; CLI&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl --aws-sigv4&lt;/code&gt; with the instance role&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iptables -t nat ... MASQUERADE&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;one nftables ruleset, applied atomically&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Jool from packages&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Jool 4.1.15 modules built against natkit&amp;rsquo;s kernel&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;CloudWatch agent installed&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;CloudWatch agent pulled by digest at boot, only when enabled&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;SSH / SSM&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;EC2 Serial Console (root password hash from SSM, optional)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;code&gt;natkit-init&lt;/code&gt; follows fck-nat&amp;rsquo;s &lt;code&gt;service/fck-nat.sh&lt;/code&gt; (MIT, Andrew Guenther).&lt;/p&gt;</description></item><item><title>Building</title><link>https://natkit.ulm0.com/docs/building/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://natkit.ulm0.com/docs/building/</guid><description>&lt;p&gt;Everything builds natively for the Docker daemon&amp;rsquo;s architecture (arm64 or amd64):&lt;/p&gt;&#10;&#10;&#10;&#10; &#10; &#10; &#10;&#10; &#10; &#10; &#10; &#10;&#10; &#10;&#10; &lt;div class="prism-codeblock "&gt;&#10; &lt;pre id="381acb5" class="language-sh "&gt;&#10; &lt;code&gt;make jool # Jool modules for natkit.yml&amp;#39;s kernel (lk-kernel); or let linuxkit pull them from GHCR&#10;make # out/natkit-&amp;lt;arch&amp;gt;-efi.img&#10;make test # natkit-init against a mock IMDS/EC2/SSM&#10;make ami # needs AWS credentials, AWS_REGION, NATKIT_BUCKET and the vmimport role&lt;/code&gt;&#10; &lt;/pre&gt;&#10; &lt;/div&gt;&#10;&lt;h2 id="ci"&gt;CI &lt;a href="#ci" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;.github/workflows/build.yml&lt;/code&gt; builds both architectures on every push. Tags (&lt;code&gt;v*&lt;/code&gt;) and manual runs also register the AMIs and run &lt;code&gt;scripts/boot-test.sh&lt;/code&gt;, which checks:&lt;/p&gt;</description></item></channel></rss>