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: add service discovery for kong admin service #3421

Merged
merged 4 commits into from
Feb 9, 2023
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
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,13 @@ Adding a new version? You'll need three changes:
[#3507](https://github.com/Kong/kubernetes-ingress-controller/pull/3507)
- Enable `ReferenceGrant` if `Gateway` feature gate is turned on (default).
[#3519](https://github.com/Kong/kubernetes-ingress-controller/pull/3519)
- Added Konnect client to upload status of KIC instance to Konnect cloud if
- Added Konnect client to upload status of KIC instance to Konnect cloud if
flag `--konnect-sync-enabled` is set to `true`.
[#3469](https://github.com/Kong/kubernetes-ingress-controller/pull/3469)
- Added service discovery for kong admin service configured via `--kong-admin-svc`
which accepts a namespaced name of headless kong admin service which should have
Admin API endpoints exposed under a named port called `admin`
[#3421](https://github.com/Kong/kubernetes-ingress-controller/pull/3421)

### Fixed

Expand Down
8 changes: 8 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ rules:
- get
- patch
- update
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ spec:
containers:
- name: ingress-controller
env:
- name: CONTROLLER_LOG_LEVEL
value: debug
- name: CONTROLLER_KONG_ADMIN_SVC
value: kong/kong-admin
image: kic-placeholder:placeholder
- name: CONTROLLER_KONG_ADMIN_URL
$patch: delete
8 changes: 8 additions & 0 deletions deploy/single/all-in-one-dbless-k4k8s-enterprise.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,14 @@ rules:
- get
- patch
- update
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
Expand Down
8 changes: 8 additions & 0 deletions deploy/single/all-in-one-dbless-konnect.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,14 @@ rules:
- get
- patch
- update
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
Expand Down
14 changes: 9 additions & 5 deletions deploy/single/all-in-one-dbless-multi-gw.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,14 @@ rules:
- get
- patch
- update
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
Expand Down Expand Up @@ -1650,12 +1658,8 @@ spec:
automountServiceAccountToken: false
containers:
- env:
- name: CONTROLLER_LOG_LEVEL
value: debug
- name: CONTROLLER_KONG_ADMIN_SVC
value: kong/kong-admin
- name: CONTROLLER_KONG_ADMIN_URL
value: https://127.0.0.1:8444
- name: CONTROLLER_KONG_ADMIN_TLS_SKIP_VERIFY
value: "true"
- name: CONTROLLER_PUBLISH_SERVICE
Expand All @@ -1670,7 +1674,7 @@ spec:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
image: kic-placeholder:placeholder
image: kong/kubernetes-ingress-controller:2.8.1
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
Expand Down
8 changes: 8 additions & 0 deletions deploy/single/all-in-one-dbless.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,14 @@ rules:
- get
- patch
- update
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
Expand Down
8 changes: 8 additions & 0 deletions deploy/single/all-in-one-postgres-enterprise.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,14 @@ rules:
- get
- patch
- update
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
Expand Down
8 changes: 8 additions & 0 deletions deploy/single/all-in-one-postgres.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,14 @@ rules:
- get
- patch
- update
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
Expand Down
24 changes: 24 additions & 0 deletions internal/adminapi/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package adminapi

import (
"context"

"github.com/kong/go-kong/kong"

"github.com/kong/kubernetes-ingress-controller/v2/internal/util"
Expand Down Expand Up @@ -76,3 +78,25 @@ func (c *Client) SetLastConfigSHA(s []byte) {
func (c *Client) LastConfigSHA() []byte {
return c.lastConfigSHA
}

type ClientFactory struct {
workspace string
httpClientOpts HTTPClientOpts
adminToken string
}

func NewClientFactoryForWorkspace(workspace string, httpClientOpts HTTPClientOpts, adminToken string) ClientFactory {
return ClientFactory{
workspace: workspace,
httpClientOpts: httpClientOpts,
adminToken: adminToken,
}
}

func (cf ClientFactory) CreateAdminAPIClient(ctx context.Context, address string) (Client, error) {
httpclient, err := MakeHTTPClient(&cf.httpClientOpts, cf.adminToken)
if err != nil {
return Client{}, err
}
return NewKongClientForWorkspace(ctx, address, cf.workspace, httpclient)
}
23 changes: 21 additions & 2 deletions internal/adminapi/kong.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (
"fmt"
"net/http"
"os"
"strings"

"github.com/kong/go-kong/kong"
"github.com/samber/lo"

tlsutil "github.com/kong/kubernetes-ingress-controller/v2/internal/util/tls"
)
Expand Down Expand Up @@ -67,8 +69,12 @@ type HTTPClientOpts struct {
TLSClient TLSClientConfig
}

const (
headerNameAdminToken = "Kong-Admin-Token"
)

// MakeHTTPClient returns an HTTP client with the specified mTLS/headers configuration.
func MakeHTTPClient(opts *HTTPClientOpts) (*http.Client, error) {
func MakeHTTPClient(opts *HTTPClientOpts, kongAdminToken string) (*http.Client, error) {
var tlsConfig tls.Config

if opts.TLSSkipVerify {
Expand Down Expand Up @@ -118,8 +124,21 @@ func MakeHTTPClient(opts *HTTPClientOpts) (*http.Client, error) {
transport.TLSClientConfig = &tlsConfig
return &http.Client{
Transport: &HeaderRoundTripper{
headers: opts.Headers,
headers: prepareHeaders(opts.Headers, kongAdminToken),
rt: transport,
},
}, nil
}

func prepareHeaders(headers []string, kongAdminToken string) []string {
if kongAdminToken != "" {
contains := lo.ContainsBy(headers, func(header string) bool {
return strings.HasPrefix(header, headerNameAdminToken+":")
})

if !contains {
headers = append(headers, headerNameAdminToken+":"+kongAdminToken)
}
}
return headers
}
66 changes: 45 additions & 21 deletions internal/adminapi/kong_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Expand All @@ -30,9 +29,7 @@ func TestMakeHTTPClientWithTLSOpts(t *testing.T) {
var err error

caPEM, certPEM, certPrivateKeyPEM, err = buildTLS(t)
if err != nil {
t.Errorf("Fail to build TLS certificates - %s", err.Error())
}
require.NoError(t, err, "Fail to build TLS certificates")

opts := HTTPClientOpts{
TLSSkipVerify: true,
Expand All @@ -46,13 +43,19 @@ func TestMakeHTTPClientWithTLSOpts(t *testing.T) {
},
}

httpclient, err := MakeHTTPClient(&opts)
require.NoError(t, err)

assert.NotNil(t, httpclient)
t.Run("without kong admin token", func(t *testing.T) {
httpclient, err := MakeHTTPClient(&opts, "")
require.NoError(t, err)
require.NotNil(t, httpclient)
require.NoError(t, validate(t, httpclient, caPEM, certPEM, certPrivateKeyPEM, ""))
})

err = validate(t, httpclient, caPEM, certPEM, certPrivateKeyPEM)
require.NoError(t, err)
t.Run("with kong admin token", func(t *testing.T) {
httpclient, err := MakeHTTPClient(&opts, "my-token")
require.NoError(t, err)
require.NotNil(t, httpclient)
require.NoError(t, validate(t, httpclient, caPEM, certPEM, certPrivateKeyPEM, "my-token"))
})
}

func TestMakeHTTPClientWithTLSOptsAndFilePaths(t *testing.T) {
Expand All @@ -62,9 +65,7 @@ func TestMakeHTTPClientWithTLSOptsAndFilePaths(t *testing.T) {
var err error

caPEM, certPEM, certPrivateKeyPEM, err = buildTLS(t)
if err != nil {
t.Errorf("Fail to build TLS certificates - %s", err.Error())
}
require.NoError(t, err, "Fail to build TLS certificates")

caFile, err := os.CreateTemp(os.TempDir(), "ca.crt")
require.NoError(t, err)
Expand Down Expand Up @@ -99,13 +100,19 @@ func TestMakeHTTPClientWithTLSOptsAndFilePaths(t *testing.T) {
},
}

httpclient, err := MakeHTTPClient(&opts)
require.NoError(t, err)

assert.NotNil(t, httpclient)
t.Run("without kong admin token", func(t *testing.T) {
httpclient, err := MakeHTTPClient(&opts, "")
require.NoError(t, err)
require.NotNil(t, httpclient)
require.NoError(t, validate(t, httpclient, caPEM, certPEM, certPrivateKeyPEM, ""))
})

err = validate(t, httpclient, caPEM, certPEM, certPrivateKeyPEM)
require.NoError(t, err)
t.Run("with kong admin token", func(t *testing.T) {
httpclient, err := MakeHTTPClient(&opts, "my-token")
require.NoError(t, err)
require.NotNil(t, httpclient)
require.NoError(t, validate(t, httpclient, caPEM, certPEM, certPrivateKeyPEM, "my-token"))
})
}

func buildTLS(t *testing.T) (caPEM *bytes.Buffer, certPEM *bytes.Buffer, certPrivateKeyPEM *bytes.Buffer, err error) {
Expand Down Expand Up @@ -222,6 +229,7 @@ func validate(t *testing.T,
caPEM *bytes.Buffer,
certPEM *bytes.Buffer,
certPrivateKeyPEM *bytes.Buffer,
kongAdminToken string,
) (err error) {
serverCert, err := tls.X509KeyPair(certPEM.Bytes(), certPrivateKeyPEM.Bytes())
if err != nil {
Expand All @@ -242,6 +250,23 @@ func validate(t *testing.T,

successMessage := "connection successful"
server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if kongAdminToken != "" {
v, ok := r.Header[http.CanonicalHeaderKey(headerNameAdminToken)]
if !ok {
fmt.Fprintf(w, "%s header not found", headerNameAdminToken)
return
}
if len(v) != 1 {
fmt.Fprintf(w, "%s header expected to contain %s but found %v",
headerNameAdminToken, kongAdminToken, v)
return
}
if v[0] != kongAdminToken {
fmt.Fprintf(w, "%s header expected to contain %s but found %s",
headerNameAdminToken, kongAdminToken, v[0])
return
}
}
fmt.Fprintln(w, successMessage)
}))
server.TLS = serverTLSConf
Expand All @@ -264,8 +289,7 @@ func validate(t *testing.T,

body := strings.TrimSpace(string(data[:]))
if body != successMessage {
t.Errorf("Invalid server response")
return err
return fmt.Errorf("invalid server response: %s", body)
}

return nil
Expand Down
Loading