The server
subcommand of the setec
command line tool implements an
HTTP server for the setec API. The server uses tsnet to
join a tailnet of your choosing.
The CLI is written in Go. To install the command-line tool, either:
go install github.com/tailscale/setec/cmd/setec@latest
or clone this repository and build it from source:
git clone https://github.com/tailscale/setec
cd setec
go build ./cmd/setec
The rest of this document assumes you have the setec
command-line tool
somewhere in your $PATH
.
Run setec help server
for a summary of command-line options. To run the
server you must provide at least a --hostname
for the service to use, and a
--state-dir
path where it will store its persistent state.
The first time you run the server you must also provide a Tailscale auth
key via the TS_AUTHKEY
environment variable, so that the server can
join your tailnet. You can omit this on subsequent invocations -- the server
will use the contents of the specified --state-dir
to reconnect to the same
tailnet.
The server stores secrets in an encrypted file in the state directory. When the server starts, it requires an access key to unlock the database.
In production, the server fetches an access key from an AWS KMS secret, whose
ARN is specified via the --kms-key-name
flag. As of 05-May-2024, AWS KMS is
the only supported production access key store; we may add others in the
future.
This mode also requires access to the AWS APIs: If you are running the server
in AWS (e.g., an EC2 VM), you would typically grant access to the key via an
IAM role on the VM. Alternatively, you can plumb in credentials via environment
variables, for example using aws-vault
or similar.
For development and testing purposes, the server also supports a --dev
flag,
which runs using a "dummy" static access key. This mode is not secure for
production use, but is useful for testing and debugging integrations locally.
Note
In the examples below, you must provide a real value for TS_AUTHKEY
obtained from your tailnet's admin panel. The value shown below
is a fake key that will not work.
-
To run a setec server in development mode under the hostname
setec-dev
:TS_AUTHKEY=tskey-auth-kf4k3k3y4testCNTRL-ZmFrZSBrZXkgZm9yIHRlc3Q setec server \ --hostname=setec-dev \ --state-dir=$HOME/setec-dev \ --dev
-
To run a setec server in production mode under the hostname
secrets
:TS_AUTHKEY=tskey-auth-kf4k3k3y4testCNTRL-ZmFrZSBrZXkgZm9yIHRlc3Q setec server \ --hostname=secrets \ --state-dir=$HOME/setec-state \ --kms-key-name=arn:aws:kms:us-east-1:123456789012:key/b8074b63-13c0-4345-a9d8-e236267d2af1
Note that the KMS key name shown here is a fake one, you must replace it with a real one from your own account. You may also need to set up other AWS environment variables (e.g.
AWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
). For example, usingaws-vault
it might look like this:TS_AUTHKEY=tskey-auth-kf4k3k3y4testCNTRL-ZmFrZSBrZXkgZm9yIHRlc3Q aws-vault exec myaccount -- \ setec -server \ --hostname=setec-dev \ --state-dir=$HOME/setec-dev \ --kms-key-name=arn:aws:kms:us-east-1:123456789012:key/b8074b63-13c0-4345-a9d8-e236267d2af1
Once you have run the server, you can grant access to it via your tailnet ACL. For example, if we assume your server's Tailscale address is 100.64.5.6, the following ACL grants would give the administrators of your tailnet full access to all secrets in your service via the API:
"grants": [
{
"ip": ["*"],
"src": ["autogroup:admin"],
"dst": ["100.64.5.6"],
// Alternatively, assign your node a tag, e.g., tag:secrets, and
// use the tag as the dst instead.
},
{
"src": ["autogroup:admin"],
"dst": ["100.64.5.6"],
"app": {
"tailscale.com/cap/secrets": [
{
"action": ["get", "info", "put", "activate", "delete"],
"secret": ["*"],
},
],
},
},
],
In practice, you will want to scope these permissions more narrowly, e.g.,
granting "get"
permission for individual secrets only to the servers that
need those values.
To test that this is working properly on a new server, try:
echo -n "hello, world" | setec -s https://setec-dev.example.ts.net put dev/hello-world
(replacing example.ts.net
with your tailnet name). This should print:
Read 12 bytes from stdin
Secret saved as "dev/hello-world", version 1
Assuming that works, you should then be able to run:
setec -s https://setec-dev.example.ts.net list
which should give you output like:
NAME ACTIVE VERSIONS
dev/hello-world 1 1
Note that the first time you call the server, it may take thirty seconds or longer as the server will need to obtain a TLS certificate from LetsEncrypt. Subsequent calls will run faster.
When running setec in production, you will generally want to keep backups of
your secrets data. The setec server
command has basic support for automatic
backups to S3 via the optional --backup-bucket
and --backup-bucket-region
flags. When these are set, the server automatically backs up the database to a
timestamped object in S3 up to once per minute, if its contents have changed
since the last backup.
The uploaded backups are fully encrypted.
While running, the server appends a basic audit log of all secret accesses to a
file called audit.log
in its state directory. These logs can be used to check
which secrets were accessed when, by which users and/or services on the
tailnet. For now (as of 05-May-2024), the audit logs are stored only in the
server's state directory.