Security
What's protected: your cloud accounts, whose keys lnk cloud keeps, and
the machines lnk box makes in them, against anyone but you reaching
them. Neither plugin talks to the relay, and Local Link holds no cloud
account: everything runs in, and is billed to, yours. What they do is
clouds and boxes. What's on a box, its install, its
workers and its users: What's on a Box; an image's:
Box Images.
Limits
What Link makes boxes on, and what it needs here to reach them.
- AWS and Google Cloud only, in your own accounts and bills.
- Boxes are Ubuntu 24.04 or 22.04 LTS on x86_64 or arm64; an arm64 box has no GPUs.
- Boxes need the cloud's CLI (
aws,gcloud) and OpenSSH on your computer.lnk box createstops before making anything whensshorssh-keygenis missing.
Cloud accounts
Where your cloud keys are kept, how each plugin acts as an account, and the adapters and CLIs that run with them.
Keys
A cloud account's keys are kept in Link's settings folder, or the Keychain, and reach the cloud's CLI only in its environment.
- A reused aws login (
~/.aws) is named, not copied: the AWS CLI, and rclone for buckets, read it when they run. - A Google Cloud account is one credential file, kept in
~/.lnk/gcp/credentials/<name>.json, mode 600 in a 700 folder: a service account's key (--credential-file), or your login's application default credentials, made once bygcloud auth application-default loginand copied there.lnk cloud disconnectdeletes it. - gcloud (with a service account's key), rclone and Google's libraries all act as that file, so boxes and buckets are the same identity. It holds a refresh token or a private key: anyone who reads it acts as the account.
- For a result-upload URL, gcloud receives the connected service account's
credential-file path with
--private-key-file. The private key's value stays in the file. The shell cannot select a different signing identity. - Every other plugin acts as an account through its adapter only, with
the account
lnk cloud envgives:lnk bucketasks the adapter'sstoragefor its sign-in on each command, and keeps none of it. - An access key given instead is kept in
~/.lnk/cloud/accounts.toml, mode 600 in a 700 folder, aslnk bucketkeeps its own. On a Mac its secret part is in the Keychain instead (Secrets in the Keychain). - A key reaches the CLI only in its environment, never on a command line, where other local users could see it.
- The shell's own
AWS_*andCLOUDSDK_*variables are removed first, so a profile set in the shell can't redirect a call to another account. - Adapters print an account on stdout to the plugin that ran them.
lnk cloud listnever includes keys;lnk cloud envdoes.
Adapters
lnk-aws and lnk-gcp run with your keys and the cloud's CLI. They're
plugins like any other: installed only from Link's signed release, found
next to lnk, else on the PATH.
The cloud's CLI
Link uses the CLI on your PATH, else one lnk cloud connect installed
when you said yes: AWS's installer from awscli.amazonaws.com into
~/.lnk/aws (on Linux, its zip and install script; on macOS, its
package, for the current user only), or Google's archive from
dl.google.com into ~/.lnk/gcp.
How they're fetched
Both come over HTTPS only. Link doesn't pin them or check their signatures: it trusts those sites, as their own install instructions do. Neither needs administrator rights, and neither changes your shell's settings.
Reaching a box
What a box lets in, how Link knows which boxes are yours and their host keys, and what each SSH connection to a box hands it.
What a box exposes
A box opens SSH alone, to Link's short-lived certificates, and its metadata service gives no cloud credentials.
- Only SSH, port 22, open to the whole internet, or no port at all on AWS through the tunnel (below). Key-only: Ubuntu's images refuse passwords.
- A box takes a certificate this computer's authority signed, for it
alone, for an hour (Certificates). No plain key of
Link's is in its
authorized_keys. - Nothing else is open. AWS security group
lnk-boxand Google Cloud firewall rulelnk-box-sshallow only TCP 22. Link makes them the first time and removes them with the last box in their region or project. - Boxes go in the account's default VPC on AWS, and its default network
on Google Cloud. That network's own rules let in every port from
inside it, RDP and ping, so Link adds
lnk-box-denythere, refusing everything else to its boxes ahead of those rules. A rule you add yourself at a normal priority still wins. - AWS instances take instance metadata only with a session token
(IMDSv2), and have no instance role. Google Cloud instances have no
service account (
--no-service-account --no-scopes). So the metadata service, which any program on the box can reach, gives no cloud credentials: Link acts on your cloud as your account, from your computer, never as the box. - Every agent made on a box goes through Link's proxy (
lnk agent route direct --default), never straight from the box or to the cloud's metadata service.
Certificates
Each computer has an SSH certificate authority of its own, and a box trusts the authorities of the computers that reach it: a copied key reaches nothing once its certificates expire, at most an hour later.
Who holds what
The authority's secret stays on the computer that made it. It's an
ed25519 secret made by ssh-keygen, kept in the Keychain on a Mac
(box/ssh-ca), else in ~/.lnk/box/ssh-ca, mode 600 in a 700 folder,
and its public half in ssh-ca.pub. It never reaches a box or a cloud.
This computer's key, ~/.lnk/box/id_ed25519, ed25519 with no
passphrase, is what a certificate certifies.
What a box trusts
A box made here trusts this computer's authority from its first boot.
Its cloud-init writes the authority's public half to
/etc/ssh/lnk/user-cas.pub and the box's principal to
/etc/ssh/lnk/principals/ubuntu, both root's. A drop-in,
/etc/ssh/sshd_config.d/10-lnk.conf, points sshd's TrustedUserCAKeys
and AuthorizedPrincipalsFile at them. The first boot also drops
Link's plain keys from authorized_keys, so a box made from an older
image takes none.
A certificate
A certificate names one principal, lnk-box-<machine id>, so it
reaches one box. It lasts an hour, from five minutes before it's
signed, and allows a terminal and forwarded ports, never your agent or
X11. Before a connection, lnk box signs a new one with ssh-keygen -s
when the box's in ~/.lnk/box/certs/ is over half an hour old. The
secret is written to a 700 folder of ~/.lnk/box while ssh-keygen
reads it, then removed.
Boxes made before certificates
A box made before certificates is given them the next time Link reaches
it. Link gets in with this computer's key and adds the authority and
the principal as a first boot would. Once a certificate alone gets in,
Link's plain keys go, through the adapter's remove-keys and from
authorized_keys, anyone else's kept. A box with no machine ID yet
keeps the key until lnk box list reads its ID.
Which boxes are yours
Link knows a box as yours by its tags, which are as trusted as the cloud account.
- Each box's machine is named
lnk-<machine id>and tagged with its name (lnk-box), its machine ID (lnk-machine) and your account's owner ID (lnk-owner=acct-<id>), or a digest of the local user and machine name while signed out (lnk-owner=local-<digest>). On AWS its disk has the same tags, so the bill says whose each disk is. lnk box listasks each connected account for the boxes with your tag, so a project shared with another Local Link user lists only yours.- Local ownership needs no Link login. A box created while this computer is signed out stays signed out; its SSH access uses the cloud account and this computer's certificates.
- The tags are as trusted as the account: anyone who can tag instances
there could make a machine look like yours. So
lnk agent move <account>asks before moving to a box it found by its tags, and takes one unasked only if this computer made it (agents). - What a listing brings back goes into file names and prompts only as a valid name and ID; anything else is skipped.
Getting in from another computer
A box made on another of your computers is reached the first time by pinning its host keys from the cloud (below). Then this computer's key is let in through the account for a moment, while the box is made to trust this computer's authority too, and then the key goes.
On Google Cloud
Merged into the instance's ssh-keys metadata, never replacing the
others, until remove-keys takes it out again. A box takes only its own keys: it's made with
block-project-ssh-keys=TRUE, so the project's SSH keys, which anyone
who can edit the project's metadata adds, don't let anyone in, and with
OS Login off. A box made before this takes them until it's made again.
On AWS
Pushed with EC2 Instance Connect, which lets it in for 60 seconds,
during which lnk box appends it to authorized_keys over SSH, to drop
it once a certificate gets in.
Each computer's key
Each computer's key has the comment lnk <machine id> <machine name>,
and its authority lnk-ca <machine id> <machine name>, so a lost
computer's can be found in /etc/ssh/lnk/user-cas.pub and removed.
Whoever controls the account could add a key this way too: the account
is trusted, as it could replace the machine anyway.
Host keys
A box's SSH host keys are pinned before the first connection, from what the cloud says, and checked on every one after.
- A new box's SSH host keys are read from its console output, the block cloud-init prints at the first boot, through the cloud's API as your account.
- They're pinned in Link's own
known_hostsbefore the first SSH connection, and kept inboxes.toml. SSH then refuses any other key:StrictHostKeyChecking=accept-newaccepts only hosts it doesn't know. - They're kept under the box's own name,
lnk-<cloud>-<its id>(ssh'sHostKeyAlias), never its address, so a box at a new address, restarted here, from the cloud's console or by another computer, is checked against the same keys. - When the console shows none within 5 minutes, or the adapter can't read it, the key is accepted on first contact and pinned after, under the box's name too. That trusts the network between you and the cloud once.
- A removed box's keys are forgotten, since its address can come back as another machine's.
- The computer that pinned them keeps them in the cloud, since the
console's first-boot output doesn't last: metadata
lnk-host-keyson Google Cloud; on AWS, the ed25519 key in alnk-host-keytag, which holds 256 characters. Another computer pins those before its first connection, and reads the console only when the cloud keeps none. - Anyone who controls the cloud account can change the host keys kept there.
One connection per box
The SSH calls a command makes to one box share one connection, which any program running as you can use while it's open.
- The
lnk box runcalls a command makes to one box share one SSH connection, which the first opens with the key and host keys above. It closes a minute after the last one ends, and when the box is removed or a new box gets its address. - Its socket is in
~/.lnk/box/mux, a 700 folder. While it's open, any program running as you can run commands on the box through it without the key, as it could with the key and the authority's secret, which it can read too. - When that folder's path is too long for a socket (over 42 characters), each call connects on its own.
Through the cloud's tunnel
With LNK_BOX_SSH=tunnel, where port 22 can't be reached, every
connection to a box goes through its cloud's own tunnel over HTTPS
instead: ssh's ProxyCommand is the box's adapter's tunnel, which
runs AWS Systems Manager's AWS-StartSSHSession or Google Cloud's
start-iap-tunnel as the box's account. An AWS box made so opens no
port: its security group, lnk-box-tunnel, made and removed like
lnk-box, lets nothing in.
Still SSH
It's still SSH, end to end, with Link's certificate, and the box's host key checked as it was pinned: the tunnel carries the bytes and sees none of them in the clear.
Who can open a tunnel
Anyone the cloud lets open a session or an IAP tunnel to the box can
open one: on AWS, whoever is allowed ssm:StartSession on the
instance; on Google Cloud, whoever has
roles/iap.tunnelResourceAccessor in its project. They still meet the
box's SSH, which takes only Link's certificates.
Systems Manager's other documents
On AWS, the box's Systems Manager agent also takes other documents, a
shell as ssm-user among them, which needs no SSH key: give the users
that open tunnels ssm:StartSession on AWS-StartSSHSession alone
(live tests, "Boxes from a cloud session").
Its ProxyCommand
It names the adapter, the account, the box's place and its id, each
refused unless it's letters, digits, dots, dashes and underscores, none
first a dash, and each quoted for the shell ssh runs it with. The
account's credentials reach the cloud's CLI in its environment, never
on a command line; AWS's own short-lived session token is on
session-manager-plugin's, as aws ssm start-session runs it.
Your own SSH config
Every connection to a box runs your ssh, which reads your
~/.ssh/config, so a ProxyJump you need still works. What would hand
the box something of this computer is turned off on the command line,
which wins over that file:
ForwardAgent=no: a box never gets your SSH agent, which would let whoever controls it sign as you to any host your keys reach.ForwardX11=no, andPermitLocalCommand=no, so noLocalCommandruns here.ClearAllForwardings=yes, on every connection butlnk box forward's, so noLocalForward,RemoteForwardorDynamicForwardof yours opens.lnk box forwardexists to forward one port or socket, and ssh can't clear the file's without clearing it too: a forward of yours underHost *opens on that connection as well.
Spot boxes
A spot box the cloud takes back is stopped, never deleted: its disk,
with its lnk login and an agent's state, stays, and is billed, without
you stopping it. What a spot box does on each cloud: box
spec.
Removing
lnk box delete deletes the machine and its disk: on AWS it's
terminated, its volume deleted with it; on Google Cloud it's deleted
with --delete-disks all. Snapshots or anything else you made there
yourself stay. Images you saved stay until lnk box image delete. A
lnk box create whose machine couldn't be made deletes what Link made
for boxes the same way.
Disconnecting
lnk cloud disconnect forgets the account and its key, and deletes
nothing in it: Disconnect an
account.
Gaps
What Link doesn't protect, as each is today.
- Keys are in a file, and so is the SSH authority's secret off a Mac: whoever reads it can sign certificates for every box this computer reaches.
- SSH is open to the internet.
- The first contact's host key is trusted when neither the cloud nor a box's console has it.
- The cloud account is trusted for tags, keys, host keys and a box's
first boot, and for
what
lnk box specprints of a box. --yesmakes a box from a spec without asking, however new the spec. What it makes is printed first.- An image holds whatever else is on the box's disk: Link checks for its own login, agents and the usual places secrets are left in the home folder, not for a secret anywhere else.
- Two images of one name in a Google Cloud project shared with another Local Link user collide: the second save is refused.
See Known limitations.
Deadlines
A deadline is installed while the instance is made. On AWS the root-owned timer survives reboot; root can change it, so it is not a wall against a process running as root. On Google Cloud the cloud enforces deletion; no guest poweroff timer is installed because stopping the VM clears its scheduled deletion.
Attached resources
What a box gets of the resources its spec's [attach] names, which it
never makes or deletes.
An attached identity
An attached identity is the existing service account or instance profile the spec names. Its metadata credentials reach whatever that identity is granted; grant only the service's resources.
Kept at removal
Attach lookups never create networks, firewall rules, addresses, identities or data disks. GCP removal deletes the boot disk alone; attached GCP disks have auto-delete disabled, and attached AWS volumes have DeleteOnTermination disabled.
Inventory by tag
Tag-based inventory queries fail on cloud errors and do not rely on the caller's login ownership label.