Skip to content

Commit

Permalink
[v17] tbot env variable configurations (#52351)
Browse files Browse the repository at this point in the history
* `tbot` add env var configs

* add `start` cmd to tbot-distroless images

* Update CLI reference

---------

Co-authored-by: Noah Stride <[email protected]>
  • Loading branch information
taraspos and strideynet authored Feb 21, 2025
1 parent bbaee7a commit 9f0c05c
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 18 deletions.
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)
})
}
}

0 comments on commit 9f0c05c

Please sign in to comment.