> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://rivet.chrisboulton.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://rivet.chrisboulton.com/_mcp/server.

# SSH authorized key

> Manage one public-key entry while preserving unrelated authorization text.

```hcl
ssh_key "deployment" {
  user    = "deploy"
  source  = "assets/deploy.pub"
  options = ["restrict", "from=\"192.0.2.0/24\""]
  comment = "deployment access"
}
```

`ssh_key` manages one entry in an `authorized_keys` file and leaves every other line alone. Give the key inline with `key` or as a file with `source`; either way it must be a single OpenSSH public key, and it is needed for `ensure = "absent"` too. An entry is identified by the key itself and the file it's in, not its comment or options, so declaring the same key twice for one file is an error.

Without `authorized_keys`, the file is `~/.ssh/authorized_keys` in the user's home directory, looked up on the host when applying. A managed user is ordered before its keys, and when both are removed, the key goes first.

With `manage_permissions = true` (the default), the `.ssh` directory and file get modes 0700 and 0600, owned by the user and their primary group. Every key in the same file must use the same permission settings, and a `file` resource managing the same file or directory conflicts. With `manage_permissions = false`, existing ownership and modes are kept, and the directory must already exist.

`options` is a list of OpenSSH restrictions such as `restrict` or `from="..."`, one per item. Unknown options, unbalanced quotes, and newlines are refused. Without `comment`, the key's own comment is used.

Each change re-reads the file, merges in the entry, and writes it atomically under the host lock, so several keys in one file are handled safely and independently. Rivet doesn't create a missing file or directory just to remove a key. The file and its parent directories can't be symlinks. sshd doesn't need restarting.

## Attributes

| Attribute            | Default                  | Behavior                                                                           |
| -------------------- | ------------------------ | ---------------------------------------------------------------------------------- |
| `user`               | Required                 | Receiving local username.                                                          |
| `ensure`             | `present`                | `present` or `absent`; both require the key identity.                              |
| `key`                | Alternative to source    | Inline single OpenSSH public key.                                                  |
| `source`             | Alternative to key       | Single-key local bundled asset, relative to the module or configuration directory. |
| `comment`            | Supplied key comment     | Optional replacement comment.                                                      |
| `options`            | Empty                    | Individually validated restriction strings.                                        |
| `authorized_keys`    | Resolved local home path | Optional explicit absolute authorization file.                                     |
| `manage_permissions` | `true`                   | Manage directory and file ownership and permissions.                               |
| `directory_mode`     | `0700`                   | Octal string.                                                                      |
| `file_mode`          | `0600`                   | Octal string.                                                                      |

Supply your actual public key in `assets/deploy.pub` for the example above. Key/source are mutually exclusive; exactly one non-null value is required. Comment and explicit authorization path permit null as omission. There is no cloud source or checksum attribute; bundled bytes still have verified asset digests. Managed permissions must not give other principals write access.

All [common metadata](/language/metadata) applies. The default budget is 60 seconds; capability is `ssh_key.native.v1`. Static exports are `user`, `ensure`, explicitly supplied `authorized_keys`, and `meta.sensitive`. A runtime-derived default authorization path cannot be exported.

This resource is unrelated to running Rivet [over SSH](/operations/ssh).