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

feat: provide Kong admin token via file #4808

Merged
merged 10 commits into from
Oct 11, 2023
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ Adding a new version? You'll need three changes:
- Only Kong Gateway in version >= 3.4.1 is supported. The controller will refuse to start
if the version is lower, also won't discover such Kong Gateways.
[#4766](https://github.com/Kong/kubernetes-ingress-controller/pull/4766)
- Added `--kong-admin-token-file` flag to provide the Kong admin token via file
[Providing Kong admin token via file](https://github.com/Kong/deck/blob/main/CHANGELOG.md#v1120).
[#4808](https://github.com/Kong/kubernetes-ingress-controller/pull/4808)


### Fixed

Expand Down
1 change: 1 addition & 0 deletions docs/cli-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
| `--kong-admin-tls-server-name` | `string` | SNI name to use to verify the certificate presented by Kong in TLS. | |
| `--kong-admin-tls-skip-verify` | `bool` | Disable verification of TLS certificate of Kong's Admin endpoint. | `false` |
| `--kong-admin-token` | `string` | The Kong Enterprise RBAC token used by the controller. | |
| `--kong-admin-token-file` | `string` | Path to the Kong Enterprise RBAC token file used by the controller. | |
| `--kong-admin-url` | `stringSlice` | Kong Admin URL(s) to connect to in the format "protocol://address:port". More than 1 URL can be provided, in such case the flag should be used multiple times or a corresponding env variable should use comma delimited addresses. | `[http://localhost:8001]` |
| `--kong-workspace` | `string` | Kong Enterprise workspace to configure. Leave this empty if not using Kong workspaces. | |
| `--konnect-address` | `string` | Base address of Konnect API. | `https://us.kic.api.konghq.com` |
Expand Down
16 changes: 16 additions & 0 deletions internal/manager/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package manager

import (
"fmt"
"os"
"time"

"github.com/samber/mo"
Expand Down Expand Up @@ -48,6 +49,7 @@ type Config struct {
KongAdminInitializationRetries uint
KongAdminInitializationRetryDelay time.Duration
KongAdminToken string
KongAdminTokenPath string
KongWorkspace string
AnonymousReports bool
EnableReverseSync bool
Expand Down Expand Up @@ -156,6 +158,7 @@ func (c *Config) FlagSet() *pflag.FlagSet {
flagSet.UintVar(&c.KongAdminInitializationRetries, "kong-admin-init-retries", 60, "Number of attempts that will be made initially on controller startup to connect to the Kong Admin API")
flagSet.DurationVar(&c.KongAdminInitializationRetryDelay, "kong-admin-init-retry-delay", time.Second*1, "The time delay between every attempt (on controller startup) to connect to the Kong Admin API")
flagSet.StringVar(&c.KongAdminToken, "kong-admin-token", "", `The Kong Enterprise RBAC token used by the controller.`)
flagSet.StringVar(&c.KongAdminTokenPath, "kong-admin-token-file", "", `Path to the Kong Enterprise RBAC token file used by the controller.`)
flagSet.StringVar(&c.KongWorkspace, "kong-workspace", "", "Kong Enterprise workspace to configure. Leave this empty if not using Kong workspaces.")
flagSet.BoolVar(&c.AnonymousReports, "anonymous-reports", true, `Send anonymized usage data to help improve Kong`)
flagSet.BoolVar(&c.EnableReverseSync, "enable-reverse-sync", false, `Send configuration to Kong even if the configuration checksum has not changed since previous update.`)
Expand Down Expand Up @@ -284,6 +287,19 @@ func (c *Config) FlagSet() *pflag.FlagSet {
return flagSet
}

func (c *Config) Resolve() error {
ludovic-pourrat marked this conversation as resolved.
Show resolved Hide resolved
if c.KongAdminToken == "" {
if c.KongAdminTokenPath != "" {
ludovic-pourrat marked this conversation as resolved.
Show resolved Hide resolved
token, err := os.ReadFile(c.KongAdminTokenPath)
if err != nil {
return fmt.Errorf("failed to read --kong-admin-token-file from path '%s': %w", c.KongAdminTokenPath, err)
}
c.KongAdminToken = string(token)
}
}
return nil
}

func (c *Config) GetKubeconfig() (*rest.Config, error) {
config, err := clientcmd.BuildConfigFromFlags(c.APIServerHost, c.KubeconfigPath)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions internal/manager/config_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ func (c *Config) Validate() error {
return fmt.Errorf("can't set both --kong-admin-svc and --kong-admin-url")
}
}
if c.KongAdminToken != "" && c.KongAdminTokenPath != "" {
return errors.New("both admin token and admin token file specified, only one allowed")
}

if err := c.validateKonnect(); err != nil {
return fmt.Errorf("invalid konnect configuration: %w", err)
Expand Down
41 changes: 41 additions & 0 deletions internal/manager/config_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package manager_test
import (
"bytes"
"fmt"
"os"
"testing"

"github.com/samber/mo"
Expand Down Expand Up @@ -335,6 +336,46 @@ func TestConfigValidate(t *testing.T) {
require.NoError(t, c.Validate())
})
})

t.Run("Admin Token", func(t *testing.T) {
validWithToken := func() manager.Config {
return manager.Config{
KongAdminToken: "non-empty-token",
}
}

t.Run("admin token accepted", func(t *testing.T) {
c := validWithToken()
require.NoError(t, c.Validate())
require.NoError(t, c.Resolve())
})
})

t.Run("Admin Token Path", func(t *testing.T) {
validWithTokenPath := func() manager.Config {
tempDir := t.TempDir()
tokenFile, err := os.CreateTemp(tempDir, "kong.token")
require.NoError(t, err)
_, err = tokenFile.Write([]byte("non-empty-token"))
require.NoError(t, err)
return manager.Config{
KongAdminTokenPath: tokenFile.Name(),
}
}

t.Run("admin token path accepted", func(t *testing.T) {
c := validWithTokenPath()
require.NoError(t, c.Validate())
require.NoError(t, c.Resolve())
require.Equal(t, c.KongAdminToken, "non-empty-token")
})

t.Run("admin token and token path rejected", func(t *testing.T) {
c := validWithTokenPath()
c.KongAdminToken = "non-empty-token"
require.ErrorContains(t, c.Validate(), "both admin token and admin token file specified, only one allowed")
})
})
}

func TestConfigValidateGatewayDiscovery(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions internal/manager/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ func Run(ctx context.Context, c *Config, diagnostic util.ConfigDumpDiagnostic, d
return fmt.Errorf("failed to create admin apis discoverer: %w", err)
}

err = c.Resolve()
if err != nil {
return fmt.Errorf("failed to resolve configuration: %w", err)
}

adminAPIClientsFactory := adminapi.NewClientFactoryForWorkspace(c.KongWorkspace, c.KongAdminAPIConfig, c.KongAdminToken)

setupLog.Info("getting the kong admin api client configuration")
Expand Down