Skip to content

Import & export infra

Availability All editions — within your plan's target caps.

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.

  • 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 a name: field.
  • Targets are grouped by kind. There is one section per kind: ssh, kubernetes, database, rdp. A target therefore has neither a name nor a kind field — 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.

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)

Logical containers (tenants, environments, teams). A target opts into one with project: <name>.

FieldRequiredNotes
(key)the project name
descriptionfree text

Labels for organizing targets in the console. Independent of projects — a target may set group: <name> regardless of its project.

FieldRequiredNotes
(key)the group name
descriptionfree text
colorhex colour (e.g. "#238636"), shown as a chip

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.

FieldRequiredNotes
(key)the key’s name (used by ssh_key: references)
private_key✓*inline OpenSSH/PEM private key
passphraseset 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.

Jump hosts. Declare once, then a target routes through it with bastion: <name>.

FieldRequiredNotes
(key)the bastion name
hostjump host address
portdefault 22
usernamelogin on the bastion
forward_agenttrue/false; forward the SSH agent
credentialhow 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:

FieldApplies toNotes
hostall*required (except a Kubernetes target that supplies config)
portalldefaults per kind: 22 ssh · 443 kubernetes · 5432/3306 database · 3389 rdp
projectallby name; created if it doesn’t exist
groupallby name; created if it doesn’t exist
bastionallreferences a bastions: entry
metadataallfree-form key: value labels
credentialssh · database · rdpsee Credentials
enginedatabasepostgresql (default) or mysql
db_namedatabasedefault database to connect to
domainrdpActive Directory domain
configkubernetesinline kubeconfig; supplies host, CA and cluster credential from its current-context

The credential: block is shared by targets and bastions:

FieldNotes
kindpassword (default) · ssh_key · ssh_key_ref
usernamelogin on the target/bastion
secretthe password (kind: password) or an inline private key (kind: ssh_key)
ssh_keyfor 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>" }

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).

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, port and 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.

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.