I want to SSH into an ECS Fargate container to use Taskwarrior on the go.
Task Management and Time Tracking from Command Line with Taskwarrior and Timewarrior - sambaiz-net
iPhone (Termius)
↓ SSH
Fargate Task
└── Container (Debian)
├── tailscaled (userspace networking + SSH server)
└── EFS mount: /var/lib/tailscale
For secure connections on AWS, SSM is an option that doesn’t require exposing ports, but it can’t be used in environments like smartphones where AWS CLI doesn’t run, so I use Tailscale. Tailscale is a service that performs P2P communication with end-to-end encryption using the VPN protocol WireGuard, which is also built into the Linux kernel, after the Coordination Server returns connection information. It performs NAT traversal via UDP hole punching, so like SSM, it doesn’t require opening inbound ports.
SSH Connect to EC2 Instances through Session Manager with ssh-over-ssm - sambaiz-net
Install Tailscale.
RUN curl -fsSL https://tailscale.com/install.sh | sh
Tailscale normally uses TUN (network TUNnel) devices for routing and handling.
$ ip tuntap add dev tun0 mode tun
$ ip addr add 10.200.0.1/24 dev tun0
$ ip link set tun0 up
$ ip route | grep tun0
# 10.200.0.0/24 dev tun0 proto kernel scope link src 10.200.0.1 linkdown
$ ip tuntap del dev tun0 mode tun
However, in environments like Fargate that don’t support TUN, this method isn’t available, so run it in userspace networking mode where tailscaled acts as a SOCKS5/HTTP proxy.
$ tailscaled --state=/var/lib/tailscale/tailscaled.state --tun=userspace-networking &
Persist /var/lib/tailscale to EFS so the device is recognized as the same one after restart.
const fileSystem = new efs.FileSystem(this, 'Efs', { vpc });
const tailscaleAccessPoint = fileSystem.addAccessPoint('TailscaleAccessPoint', {
path: '/tailscale',
posixUser: { uid: '0', gid: '0' },
});
taskDef.addVolume({
name: 'tailscale-state',
efsVolumeConfiguration: {
fileSystemId: fileSystem.fileSystemId,
authorizationConfig: { accessPointId: tailscaleAccessPoint.accessPointId },
},
});
container.addMountPoints({
sourceVolume: 'tailscale-state',
containerPath: '/var/lib/tailscale',
readOnly: false,
});
Generate an authkey in the console and run tailscale up. It generates a keypair, the public key is registered with the Coordination Server and used for WireGuard encryption. The key have a default expiry of 180 days, so for server use, set Disable key expiry.
$ tailscale up --authkey="${TS_AUTHKEY}" --ssh --reset
–ssh is the flag to enable Tailscale SSH. tailscaled intercepts port 22 and handles authentication. ACL configuration is required.
{
"ssh": [
{
"action": "accept",
"src": ["autogroup:member"],
"dst": ["autogroup:self"],
"users": ["root"]
}
]
}
Using tailscale/gitops-acl-action, you can apply ACL on push.
on:
push:
paths:
- 'tailscale/policy.hujson'
jobs:
acl:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: tailscale/gitops-acl-action@v1
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tailnet: ${{ secrets.TS_TAILNET }}
policy-file: tailscale/policy.hujson
action: apply
Install the Tailscale app on your smartphone and connect to the network, then you can SSH from Termius using the device name.