Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v17] tbot env variable configurations #52351

Merged
merged 3 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.assets/charts/Dockerfile-tbot-distroless
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ RUN --mount=type=bind,target=/ctx dpkg-deb -R /ctx/$TELEPORT_DEB_FILE_NAME /opt/
FROM $BASE_IMAGE
COPY --from=teleport /opt/staging/usr/local/bin/tbot /usr/local/bin/tbot
ENTRYPOINT ["/usr/local/bin/tbot"]
CMD ["start"]
1 change: 1 addition & 0 deletions build.assets/charts/Dockerfile-tbot-distroless-fips
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ RUN --mount=type=bind,target=/ctx dpkg-deb -R /ctx/$TELEPORT_DEB_FILE_NAME /opt/
FROM $BASE_IMAGE
COPY --from=teleport /opt/staging/usr/local/bin/tbot /usr/local/bin/tbot
ENTRYPOINT ["/usr/local/bin/tbot", "--fips"]
CMD ["start"]
31 changes: 16 additions & 15 deletions docs/pages/reference/cli/tbot.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -297,22 +297,23 @@ another dedicated mode instead.

### Flags

| Flag | Description |
|----------------------|------------------------------------------------------------------------------------------------|
| `-d/--debug` | Enable verbose logging to stderr. |
| `-c/--config` | Path to a Machine ID configuration file. |
| `--[no-]fips` | Whether to run tbot in FIPS compliance mode. This requires the FIPS `tbot` binary. |
| `-a/--auth-server` | Address of the Teleport Auth Service. Prefer using --proxy-server where possible |
| `--proxy-server` | Address of the Teleport Proxy Server. |
| `--token` | A bot join token, if attempting to onboard a new bot; used on first connect. Can also be an absolute path to a file containing the token. |
| `--ca-pin` | CA pin to validate the Teleport Auth Service; used on first connect. |
| Flag | Description |
|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `-d/--debug` | Enable verbose logging to stderr. Can also be configured using the `TBOT_DEBUG` environment variable. |
| `-c/--config` | Path to a tbot configuration file. Mutually exclusive with `--config-string`. Can also be configured with the `TBOT_CONFIG_PATH` environment variable. |
| `--config-string` | Allows the tbot configuration to be provided as a base 64 string directly via this flag or the `TBOT_CONFIG` environment variable. Mutually exclusive with `--config` |
| `--[no-]fips` | Whether to run tbot in FIPS compliance mode. This requires the FIPS `tbot` binary. |
| `-a/--auth-server` | Address of the Teleport Auth Service. Prefer using --proxy-server where possible |
| `--proxy-server` | Address of the Teleport Proxy Server. |
| `--token` | A bot join token, if attempting to onboard a new bot; used on first connect. Can also be an absolute path to a file containing the token. |
| `--ca-pin` | CA pin to validate the Teleport Auth Service; used on first connect. |
| `--data-dir` | Directory to store internal bot data. In production environments access to this directory should be limited only to an isolated linux user as an owner with `0600` permissions. |
| `--destination-dir` | Directory to write short-lived machine certificates. |
| `--certificate-ttl` | TTL of short-lived machine certificates. |
| `--renewal-interval` | Interval at which short-lived certificates are renewed; must be less than the certificate TTL. |
| `--join-method` | Method to use to join the cluster. Can be `token`, `azure`, `circleci`, `gcp`, `github`, `gitlab` or `iam`. |
| `--oneshot` | If set, quit after the first renewal. |
| `--log-format` | Controls the format of output logs. Can be `json` or `text`. Defaults to `text`. |
| `--destination-dir` | Directory to write short-lived machine certificates. |
| `--certificate-ttl` | TTL of short-lived machine certificates. |
| `--renewal-interval` | Interval at which short-lived certificates are renewed; must be less than the certificate TTL. |
| `--join-method` | Method to use to join the cluster. Can be `token`, `azure`, `circleci`, `gcp`, `github`, `gitlab` or `iam`. |
| `--oneshot` | If set, quit after the first renewal. |
| `--log-format` | Controls the format of output logs. Can be `json` or `text`. Defaults to `text`. |

### Examples
<Tabs>
Expand Down
17 changes: 16 additions & 1 deletion lib/tbot/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ const (
// ProxyServerEnvVar is the environment variable that overrides the
// configured proxy server address.
ProxyServerEnvVar = "TELEPORT_PROXY"
// TBotDebugEnvVar is the environment variable that enables debug logging.
TBotDebugEnvVar = "TBOT_DEBUG"
// TBotConfigPathEnvVar is the environment variable that overrides the
// configured config file path.
TBotConfigPathEnvVar = "TBOT_CONFIG_PATH"
// TBotConfigEnvVar is the environment variable that provides tbot
// configuration with base64 encoded string.
TBotConfigEnvVar = "TBOT_CONFIG"
)

var log = logutils.NewPackageLogger(teleport.ComponentKey, teleport.ComponentTBot)
Expand Down Expand Up @@ -154,11 +162,18 @@ func LoadConfigWithMutators(globals *GlobalArgs, mutators ...ConfigMutator) (*co
var cfg *config.BotConfig
var err error

if globals.staticConfigYAML != "" {
if globals.ConfigString != "" && globals.ConfigPath != "" {
return nil, trace.BadParameter("cannot specify both config and config-string")
} else if globals.staticConfigYAML != "" {
cfg, err = config.ReadConfig(strings.NewReader(globals.staticConfigYAML), false)
if err != nil {
return nil, trace.Wrap(err)
}
} else if globals.ConfigString != "" {
cfg, err = config.ReadConfigFromBase64String(globals.ConfigString, false)
if err != nil {
return nil, trace.Wrap(err, "loading bot config from base64 encoded string")
}
} else if globals.ConfigPath != "" {
cfg, err = config.ReadConfigFromFile(globals.ConfigPath, false)

Expand Down
8 changes: 6 additions & 2 deletions lib/tbot/cli/globals.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ type GlobalArgs struct {
// ConfigPath is a path to a YAML configuration file to load, if any.
ConfigPath string

// ConfigString is a base64 encoded string of a YAML configuration file to load, if any.
ConfigString string

// Debug enables debug-level logging, when set
Debug bool

Expand All @@ -67,8 +70,9 @@ type GlobalArgs struct {
func NewGlobalArgs(app *kingpin.Application) *GlobalArgs {
g := &GlobalArgs{}

app.Flag("debug", "Verbose logging to stdout.").Short('d').BoolVar(&g.Debug)
app.Flag("config", "Path to a configuration file.").Short('c').StringVar(&g.ConfigPath)
app.Flag("debug", "Verbose logging to stdout.").Short('d').Envar(TBotDebugEnvVar).BoolVar(&g.Debug)
app.Flag("config", "Path to a configuration file.").Short('c').Envar(TBotConfigPathEnvVar).StringVar(&g.ConfigPath)
app.Flag("config-string", "Base64 encoded configuration string.").Hidden().Envar(TBotConfigEnvVar).StringVar(&g.ConfigString)
app.Flag("fips", "Runs tbot in FIPS compliance mode. This requires the FIPS binary is in use.").BoolVar(&g.FIPS)
app.Flag("trace", "Capture and export distributed traces.").Hidden().BoolVar(&g.Trace)
app.Flag("trace-exporter", "An OTLP exporter URL to send spans to.").Hidden().StringVar(&g.TraceExporter)
Expand Down
12 changes: 12 additions & 0 deletions lib/tbot/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
package config

import (
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -592,6 +594,16 @@ func ReadConfigFromFile(filePath string, manualMigration bool) (*BotConfig, erro
return ReadConfig(f, manualMigration)
}

// ReadConfigFromBase64String reads and parses a YAML config from a base64 encoded string.
func ReadConfigFromBase64String(b64Str string, manualMigration bool) (*BotConfig, error) {
data, err := base64.StdEncoding.DecodeString(b64Str)
if err != nil {
return nil, trace.Wrap(err, "failed to decode base64 encoded config")
}
r := bytes.NewReader(data)
return ReadConfig(r, manualMigration)
}

type Version string

var (
Expand Down
54 changes: 54 additions & 0 deletions lib/tbot/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,57 @@ func TestCredentialLifetimeValidate(t *testing.T) {
})
}
}

// TestBotConfig_Base64 ensures that config can be read from bas64 encoded YAML
func TestBotConfig_Base64(t *testing.T) {
tests := []struct {
name string
configBase64 string
expected BotConfig
}{
{
name: "minimal config, proxy server",
configBase64: "dmVyc2lvbjogdjIKcHJveHlfc2VydmVyOiAiZXhhbXBsZS50ZWxlcG9ydC5zaDo0NDMiCm9uYm9hcmRpbmc6CiAgdG9rZW46ICJteS10b2tlbiIKICBqb2luX21ldGhvZDogInRva2VuIgpzZXJ2aWNlczoKLSB0eXBlOiBhcHBsaWNhdGlvbi10dW5uZWwKICBhcHBfbmFtZTogdGVzdGFwcAogIGxpc3RlbjogdGNwOi8vMTI3LjAuMC4xOjgwODA=",
expected: BotConfig{
Version: V2,
ProxyServer: "example.teleport.sh:443",
Onboarding: OnboardingConfig{
JoinMethod: "token",
TokenValue: "my-token",
},
Services: []ServiceConfig{
&ApplicationTunnelService{
Listen: "tcp://127.0.0.1:8080",
AppName: "testapp",
},
},
},
},
{
name: "minimal config, auth server",
configBase64: "dmVyc2lvbjogdjIKYXV0aF9zZXJ2ZXI6ICJleGFtcGxlLnRlbGVwb3J0LnNoOjQ0MyIKb25ib2FyZGluZzoKICB0b2tlbjogIm15LXRva2VuIgogIGpvaW5fbWV0aG9kOiAidG9rZW4iCnNlcnZpY2VzOgotIHR5cGU6IGFwcGxpY2F0aW9uLXR1bm5lbAogIGFwcF9uYW1lOiB0ZXN0YXBwCiAgbGlzdGVuOiB0Y3A6Ly8xMjcuMC4wLjE6ODA4MA==",
expected: BotConfig{
Version: V2,
AuthServer: "example.teleport.sh:443",
Onboarding: OnboardingConfig{
JoinMethod: "token",
TokenValue: "my-token",
},
Services: []ServiceConfig{
&ApplicationTunnelService{
Listen: "tcp://127.0.0.1:8080",
AppName: "testapp",
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg, err := ReadConfigFromBase64String(tt.configBase64, false)
require.NoError(t, err)
require.Equal(t, tt.expected, *cfg)
})
}
}
Loading