
In this guide, we will demonstrate how to use Machine ID to access a database protected by Teleport from a custom application.
With Machine ID, Teleport issues short-lived certificates, tied to a machine identity, that can be rotated, audited, and managed with the same access controls that Teleport provides for human users.
Prerequisites
You will need to be running the Teleport Proxy and Auth Services, version 9.3.0 or later.
If you have not already put your database behind Teleport Database Access, follow the Database Access Getting Started Guide. Database Access supports databases like PostgreSQL, MongoDB, Redis, and much more. See our Database Access Guides for a complete list.
If you have not already set up Machine ID, follow the Machine ID Getting
Started Guide to familiarize yourself with Machine ID.
You'll need tctl
access to initially configure the bot.
To connect to Teleport, log in to your cluster using tsh
, then use tctl
remotely:
tsh login --proxy=teleport.example.com [email protected]tctl statusCluster teleport.example.com
Version 12.1.1
CA pin sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678
You can run subsequent tctl
commands in this guide on your local machine.
For full privileges, you can also run tctl
commands on your Auth Service host.
To connect to Teleport, log in to your cluster using tsh
, then use tctl
remotely:
tsh login --proxy=myinstance.teleport.sh [email protected]tctl statusCluster myinstance.teleport.sh
Version 12.1.2
CA pin sha256:sha-hash-here
You must run subsequent tctl
commands in this guide on your local machine.
Lastly, ensure both the tbot
and tsh
executables are available on your
application host. See Installation for details.
Step 1/3. Create a Machine ID bot and assign permissions
In the example below, you will create a bot user named app
and assign
this bot user the machine-id-db
role.
First, create a role that Machine ID can use to access your database:
kind: role
version: v5
metadata:
name: machine-id-db
spec:
allow:
db_labels:
'*': '*'
db_names: [example]
db_users: [alice]
rules:
- resources: [db_server, db]
verbs: [read, list]
This role allows Machine ID bots to do two things:
- Access the database
example
on any database server (due to the'*': '*'
label selector) as the useralice
. You may restrict access to the bot using a more specific label selector; see the Database Access RBAC guide for more info. - Discover information about databases in Teleport.
Write this to role.yaml
and run the following to create the role in Teleport:
tctl create -f role.yaml
With the role created, create a new bot and allow it to assume the new role.
Connect to the Teleport Auth Server and use tctl
to create the bot:
tctl bots add app --roles=machine-id-db
Step 2/3. Configure and start Machine ID
Next, we'll run Machine ID alongside our database client app to begin fetching credentials.
Start by creating a configuration file for Machine ID at /etc/tbot.yaml
:
auth_server: "teleport.example.com:443"
onboarding:
join_method: "token"
token: "abcd123-insecure-do-not-use-this"
ca_pins:
- "sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678"
storage:
directory: /var/lib/teleport/bot
destinations:
- directory: /opt/machine-id
database:
service: example-server
username: alice
database: example
# If using MongoDB, be sure to include the Mongo-formatted certificates:
configs:
- mongo
Be sure to configure the token
and ca_pins
fields to match the output from
tctl bots add ...
. We've also included the mongo
config template in the
configs
section to generate additional certificates for MongoDB; you can
remove it if using a different database type.
Machine ID also allows you to use Linux ACLs to control access to certificates on disk. You will use this to ensure only your application has access to the short-lived certificates Machine ID uses.
We'll work with the assumption you will be running Machine ID as the Linux user
teleport
and your application as the Linux user app
. Create and initialize
the destination directory by running this tbot init
command either as root
or as the teleport
user:
tbot init \ -c /etc/tbot.yaml \ --init-dir=/opt/machine-id \ --bot-user=teleport \ --owner=teleport:teleport \ --reader-user=app
Create the bot data directory and grant permissions to access it to the Linux user (in our example, teleport
) which tbot
will run as.
Make the bot directory and assign ownership to teleport user
sudo mkdir -p /var/lib/teleport/botsudo chown teleport:teleport /var/lib/teleport/botAllow teleport user to open directory
sudo chmod +x /var/lib/teleport /var/lib/teleport/bot
Be sure to re-run tbot init ...
as shown here if config templates are added
or removed from tbot.yaml
. You may run into permissions errors if tbot init
is not run for new files.
Next, you will use systemd to run Machine ID in the background on your
application node. Create a systemd.unit file at
/etc/systemd/system/machine-id.service
:
[Unit]
Description=Teleport Machine ID Service
After=network.target
[Service]
Type=simple
User=teleport
Group=teleport
Restart=on-failure
Environment="TELEPORT_ANONYMOUS_TELEMETRY=1"
ExecStart=/usr/local/bin/tbot start -c /etc/tbot.yaml
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/run/machine-id.pid
LimitNOFILE=524288
[Install]
WantedBy=multi-user.target
TELEPORT_ANONYMOUS_TELEMETRY
enables the submission of anonymous usage
telemetry. This helps us shape the future development of tbot
. You can disable
this by omitting this.
Additionally, we'll need to create a secondary service to manage the database
proxy. Create another unit file at /etc/systemd/system/machine-id-proxy.service
:
[Unit]
Description=Teleport Machine ID Proxy Service
After=network.target
Requires=machine-id.service
[Service]
Type=simple
User=teleport
Group=teleport
Restart=on-failure
ExecStart=/usr/local/bin/tbot -c /etc/tbot.yaml proxy --proxy=proxy.example.com:3080 --destination-dir=/opt/machine-id db --port=12345 example-server
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/run/machine-id-proxy.pid
LimitNOFILE=8192
[Install]
WantedBy=multi-user.target
This will start a local proxy on port 12345
applications can use to connect
to the example-server
database server. Be sure to customize the tbot
parameters as necessary for your local setup.
Finally, run the following commands to start Machine ID:
sudo systemctl enable machine-id machine-id-proxysudo systemctl start machine-id machine-id-proxysudo systemctl status machine-id machine-id-proxy
Step 3/3. Update and run your application
In the default proxy mode, database clients must also be configured to use
tbot
's generated TLS certificates. This ensures no other users of the system
can access the database via the local proxy, and ensures the connection between
your database client and server is never unencrypted, even over localhost.
The standard TLS credentials may be found in your configured destination
directory, which in this example is /opt/machine-id
. The certificate may be
found at /opt/machine-id/tlscert
along with the private key
/opt/machine-id/key
and CA at /opt/machine-id/teleport-database-ca.crt
.
These are compatible with most database clients.
Certain databases may require specially-formatted certificates. Where
supported, tbot
provides configuration templates you may configure via the
tbot.yaml
config file on a per-destination basis:
Database Type | Template Name | Description |
---|---|---|
MongoDB | mongo | Provides mongo.crt and mongo.cas |
CockroachDB | cockroach | Provides cockroach/node.key , cockroach/node.crt , and cockroach/ca.crt |
Generic TLS | tls | Provides tls.key , tls.crt , and tls.cas (for generic clients that require specific file extensions) |
The mongo
template is enabled in the example tbot.yaml
shown
above. If config template changes are needed, be sure to re-run tbot init ...
to configure the new output files, then restart tbot
with
systemctl restart machine-id machine-id-proxy
.
If desired, you can add the --tunnel
flag to the tbot proxy db ...
command in the machine-id-proxy.service
systemd unit file to
authenticate automatically at the proxy level, however this will decrease
security as all users of the system will be able to connect to the database
without any additional authentication.
Once the necessary credentials for your database are ready to use, refer to these sample Go programs to test connectivity to your database.
// This example program demonstrates how to connect to a Postgres database
// using certificates issued by Teleport Machine ID.
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/jackc/pgx/v4/stdlib"
)
func main() {
// Open connection to database.
db, err := sql.Open("pgx", fmt.Sprint(
"host=localhost ",
"port=1234 ",
"dbname=example ",
"user=alice ",
"sslmode=verify-full ",
"sslrootcert=/opt/machine-id/teleport-database-ca.crt ",
"sslkey=/opt/machine-id/key ",
"sslcert=/opt/machine-id/tlscert ",
))
if err != nil {
log.Fatalf("Failed to open database: %v.", err)
}
defer db.Close()
// Call "Ping" to test connectivity.
err = db.Ping()
if err != nil {
log.Fatalf("Failed to Ping database: %v.", err)
}
log.Printf("Successfully connected to PostgreSQL.")
}
// This example program demonstrates how to connect to a MongoDB database
// using certificates issued by Teleport Machine ID.
package main
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Create client and connect to MongoDB. Make sure to modify the host,
// port, and certificate paths.
uri := fmt.Sprintf(
"mongodb://localhost:1234/?tlsCAFile=%s&tlsCertificateKeyFile=%s",
"/opt/machine-id/mongo.cas",
"/opt/machine-id/mongo.crt",
)
client, err := mongo.NewClient(options.Client().ApplyURI(uri))
if err != nil {
log.Fatalf("Failed to create database client: %v.", err)
}
err = client.Connect(ctx)
if err != nil {
log.Fatalf("Failed to connect to database: %v.", err)
}
defer client.Disconnect(ctx)
log.Printf("Successfully connected to MongoDB.")
// List databases to test connectivity.
databases, err := client.ListDatabaseNames(ctx, bson.M{})
if err != nil {
log.Fatalf("Failed to list databases: %v.", err)
}
log.Println(databases)
}
You are all set. You have provided your application with short-lived certificates tied to a machine identity that can access your database, be rotated, and audited, all while being controlled with all the familiar Teleport access controls.