Import & export infra
Instead of clicking through the console, you can declare your whole inventory in one YAML document and apply it atomically. Import covers infrastructure only: targets of every kind (SSH, Kubernetes, database, RDP), projects and groups, the SSH key library, bastions, and per-target credentials. Users, access grants and audit history are never part of import/export — manage people via OIDC/SCIM or the Users page.
Find both actions under Settings → Import.
Format rules
Section titled “Format rules”- Everything is keyed by name. Collections (
projects,groups,ssh_keys,bastions) and targets are YAML maps, where the key is the object’s name — not lists with aname:field. - Targets are grouped by kind. There is one section per kind:
ssh,kubernetes,database,rdp. A target therefore has neither anamenor akindfield — the map key is its name, the section is its kind. - References are by name. A target points at a project, group, bastion or SSH key by that object’s name. The referenced object may be defined in the same file or already exist.
- Order doesn’t matter. Projects/groups/keys are resolved before targets regardless of where they appear.
Export produces this exact shape, so files round-trip: export → edit → import.
Complete template
Section titled “Complete template”Every section and field Tessera understands, annotated. All fields except a target’s host
(or a Kubernetes config) are optional — delete what you don’t need.
Complete annotated template
# ─────────────────────────────────────────────────────────────────────────────# COLLECTIONS — each is a map of name: { properties }# ─────────────────────────────────────────────────────────────────────────────
projects: # logical tenants / environments Production: description: Customer-facing production # optional, free text Staging: {} # description is optional
groups: # labels for organizing targets within the console web: description: Front-end fleet # optional color: "#238636" # optional, hex; shown as a chip in the UI data: {}
ssh_keys: # reusable SSH key library (referenced by name below) edge-key: private_key: | # OpenSSH/PEM private key, inline -----BEGIN OPENSSH PRIVATE KEY----- ... -----END OPENSSH PRIVATE KEY----- passphrase: "" # optional; set if the key is encrypted
bastions: # jump hosts — declared once, referenced by many targets edge: host: bastion.prod.internal # required port: 22 # optional, default 22 username: jump # login on the bastion forward_agent: false # optional; forward the SSH agent credential: # how Tessera authenticates to the bastion kind: ssh_key_ref # password | ssh_key | ssh_key_ref ssh_key: edge-key # for ssh_key_ref: a name from ssh_keys
# ─────────────────────────────────────────────────────────────────────────────# TARGETS — one section per kind: name: { properties }# ─────────────────────────────────────────────────────────────────────────────
ssh: prod-web-1: host: 10.0.4.11 # required port: 22 # optional, default 22 project: Production # optional, by name (created if absent) group: web # optional, by name (created if absent) bastion: edge # optional, references a bastions: entry metadata: # optional free-form labels env: prod owner: platform credential: kind: password # password | ssh_key | ssh_key_ref username: deploy secret: "s3cr3t" # the password (kind: password)
legacy-box: host: 10.0.4.12 credential: kind: ssh_key # an INLINE private key for this one target username: root secret: | -----BEGIN OPENSSH PRIVATE KEY----- ... -----END OPENSSH PRIVATE KEY-----
database: prod-db: host: 10.0.4.20 port: 5432 # optional, default 5432 (pg) / 3306 (mysql) project: Production group: data engine: postgresql # postgresql (default) | mysql db_name: app # default database to connect to credential: kind: password username: readonly secret: "..."
rdp: win-jump: host: 10.0.4.30 port: 3389 # optional, default 3389 project: Production domain: CORP # optional, Active Directory domain credential: kind: password username: Administrator secret: "..."
kubernetes: prod-cluster: project: Production group: data config: | # inline kubeconfig — host, CA and cluster apiVersion: v1 # credential are taken from its current-context clusters: [...] contexts: [...] users: [...] # (a kubernetes target uses `config`, NOT a `credential` block)Blocks
Section titled “Blocks”projects:
Section titled “projects:”Logical containers (tenants, environments, teams). A target opts into one with project: <name>.
| Field | Required | Notes |
|---|---|---|
| (key) | ✓ | the project name |
description | free text |
groups:
Section titled “groups:”Labels for organizing targets in the console. Independent of projects — a target may set
group: <name> regardless of its project.
| Field | Required | Notes |
|---|---|---|
| (key) | ✓ | the group name |
description | free text | |
color | hex colour (e.g. "#238636"), shown as a chip |
ssh_keys:
Section titled “ssh_keys:”The reusable SSH key library. Store a private key once and reference it from many targets
or bastions via a ssh_key_ref credential — the raw key is never repeated in the file.
| Field | Required | Notes |
|---|---|---|
| (key) | ✓ | the key’s name (used by ssh_key: references) |
private_key | ✓* | inline OpenSSH/PEM private key |
passphrase | set if the private key is encrypted |
*On export keys are redacted to public_key + fingerprint (no private_key). An entry
without a private_key is treated as a reference to an already-stored key and is not
recreated — so a redacted export re-imports cleanly.
bastions:
Section titled “bastions:”Jump hosts. Declare once, then a target routes through it with bastion: <name>.
| Field | Required | Notes |
|---|---|---|
| (key) | ✓ | the bastion name |
host | ✓ | jump host address |
port | default 22 | |
username | login on the bastion | |
forward_agent | true/false; forward the SSH agent | |
credential | how to authenticate to the bastion (see Credentials) |
Targets — ssh / database / rdp / kubernetes
Section titled “Targets — ssh / database / rdp / kubernetes”Each section is a map of name → properties. Common fields:
| Field | Applies to | Notes |
|---|---|---|
host | all* | required (except a Kubernetes target that supplies config) |
port | all | defaults per kind: 22 ssh · 443 kubernetes · 5432/3306 database · 3389 rdp |
project | all | by name; created if it doesn’t exist |
group | all | by name; created if it doesn’t exist |
bastion | all | references a bastions: entry |
metadata | all | free-form key: value labels |
credential | ssh · database · rdp | see Credentials |
engine | database | postgresql (default) or mysql |
db_name | database | default database to connect to |
domain | rdp | Active Directory domain |
config | kubernetes | inline kubeconfig; supplies host, CA and cluster credential from its current-context |
Credentials
Section titled “Credentials”The credential: block is shared by targets and bastions:
| Field | Notes |
|---|---|
kind | password (default) · ssh_key · ssh_key_ref |
username | login on the target/bastion |
secret | the password (kind: password) or an inline private key (kind: ssh_key) |
ssh_key | for kind: ssh_key_ref — the name of an ssh_keys: entry |
credential: { kind: password, username: deploy, secret: "s3cr3t" }credential: { kind: ssh_key_ref, username: root, ssh_key: edge-key }credential: { kind: ssh_key, username: root, secret: "<inline PEM>" }Behaviour
Section titled “Behaviour”Export redaction
Section titled “Export redaction”Exported credentials and private keys are redacted — the export is safe to store and diff, but it is not a credential backup. Key and bastion references (by name) are preserved. Fill secrets back in on re-import, or leave them blank to keep the existing secret (see below).
Re-importing is idempotent
Section titled “Re-importing is idempotent”Targets are matched by (kind, name). Re-importing the same file — or the same file with a few servers added — updates existing targets in place and inserts the new ones. It never creates duplicates.
project,group,host,portand connection settings are overwritten from the file.- A target’s credential is only replaced when the file provides one. A redacted re-import
(no
secret) leaves the existing credential untouched — you won’t wipe stored passwords by round-tripping an export.
Atomic apply & preview
Section titled “Atomic apply & preview”Settings → Import shows a preview (counts + validation errors) before you apply. The apply is a single transaction — if anything fails validation, nothing is written.
Import respects your edition’s limits — Community caps targets per kind (see Editions & pricing). If a file would exceed your caps, the preview flags it and the apply is blocked until you upgrade or trim the file.
We would like to count visits with Google Analytics, which needs a cookie. Nothing is loaded and nothing is stored unless you accept. What this sets.