Code changes to support Kube 0.26 deps
This commit is contained in:
parent
a430f4b730
commit
7ff3b3d9cb
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Package main is the combined entrypoint for all Pinniped server components.
|
// Package main is the combined entrypoint for all Pinniped server components.
|
||||||
@ -12,13 +12,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
|
||||||
|
|
||||||
// this side effect import ensures that we use fipsonly crypto in fips_strict mode.
|
|
||||||
concierge "go.pinniped.dev/internal/concierge/server"
|
concierge "go.pinniped.dev/internal/concierge/server"
|
||||||
|
// this side effect import ensures that we use fipsonly crypto in fips_strict mode.
|
||||||
_ "go.pinniped.dev/internal/crypto/ptls"
|
_ "go.pinniped.dev/internal/crypto/ptls"
|
||||||
lua "go.pinniped.dev/internal/localuserauthenticator"
|
lua "go.pinniped.dev/internal/localuserauthenticator"
|
||||||
"go.pinniped.dev/internal/plog"
|
"go.pinniped.dev/internal/plog"
|
||||||
|
"go.pinniped.dev/internal/psets"
|
||||||
supervisor "go.pinniped.dev/internal/supervisor/server"
|
supervisor "go.pinniped.dev/internal/supervisor/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,7 +37,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
binary := filepath.Base(os.Args[0])
|
binary := filepath.Base(os.Args[0])
|
||||||
if subcommands[binary] == nil {
|
if subcommands[binary] == nil {
|
||||||
fail(fmt.Errorf("must be invoked as one of %v, not %q", sets.StringKeySet(subcommands).List(), binary))
|
fail(fmt.Errorf("must be invoked as one of %v, not %q", psets.StringKeySet(subcommands).List(), binary))
|
||||||
}
|
}
|
||||||
subcommands[binary]()
|
subcommands[binary]()
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package impersonator
|
package impersonator
|
||||||
@ -192,7 +192,7 @@ func newInternal( //nolint:funlen // yeah, it's kind of long.
|
|||||||
defer impersonationProxyCompleted.ServeHTTP(w, r)
|
defer impersonationProxyCompleted.ServeHTTP(w, r)
|
||||||
impersonationProxy.ServeHTTP(w, r)
|
impersonationProxy.ServeHTTP(w, r)
|
||||||
}))
|
}))
|
||||||
handler = filterlatency.TrackStarted(handler, "impersonationproxy")
|
handler = filterlatency.TrackStarted(handler, c.TracerProvider, "impersonationproxy")
|
||||||
|
|
||||||
// The standard Kube handler chain (authn, authz, impersonation, audit, etc).
|
// The standard Kube handler chain (authn, authz, impersonation, audit, etc).
|
||||||
// See the genericapiserver.DefaultBuildHandlerChain func for details.
|
// See the genericapiserver.DefaultBuildHandlerChain func for details.
|
||||||
@ -201,12 +201,12 @@ func newInternal( //nolint:funlen // yeah, it's kind of long.
|
|||||||
// we need to grab the bearer token before WithAuthentication deletes it.
|
// we need to grab the bearer token before WithAuthentication deletes it.
|
||||||
handler = filterlatency.TrackCompleted(handler)
|
handler = filterlatency.TrackCompleted(handler)
|
||||||
handler = withBearerTokenPreservation(handler)
|
handler = withBearerTokenPreservation(handler)
|
||||||
handler = filterlatency.TrackStarted(handler, "bearertokenpreservation")
|
handler = filterlatency.TrackStarted(handler, c.TracerProvider, "bearertokenpreservation")
|
||||||
|
|
||||||
// Always set security headers so browsers do the right thing.
|
// Always set security headers so browsers do the right thing.
|
||||||
handler = filterlatency.TrackCompleted(handler)
|
handler = filterlatency.TrackCompleted(handler)
|
||||||
handler = securityheader.Wrap(handler)
|
handler = securityheader.Wrap(handler)
|
||||||
handler = filterlatency.TrackStarted(handler, "securityheaders")
|
handler = filterlatency.TrackStarted(handler, c.TracerProvider, "securityheaders")
|
||||||
|
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package impersonator
|
package impersonator
|
||||||
@ -58,6 +58,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestImpersonator(t *testing.T) {
|
func TestImpersonator(t *testing.T) {
|
||||||
|
const (
|
||||||
|
priorityLevelConfigurationsVersion = "v1beta3"
|
||||||
|
flowSchemasVersion = "v1beta3"
|
||||||
|
)
|
||||||
|
|
||||||
ca, err := certauthority.New("ca", time.Hour)
|
ca, err := certauthority.New("ca", time.Hour)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
caKey, err := ca.PrivateKeyToPEM()
|
caKey, err := ca.PrivateKeyToPEM()
|
||||||
@ -714,8 +719,8 @@ func TestImpersonator(t *testing.T) {
|
|||||||
secure := ptls.Secure(rootCAs)
|
secure := ptls.Secure(rootCAs)
|
||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
case "/api/v1/namespaces/kube-system/configmaps",
|
case "/api/v1/namespaces/kube-system/configmaps",
|
||||||
"/apis/flowcontrol.apiserver.k8s.io/v1beta2/prioritylevelconfigurations",
|
fmt.Sprintf("/apis/flowcontrol.apiserver.k8s.io/%s/prioritylevelconfigurations", priorityLevelConfigurationsVersion),
|
||||||
"/apis/flowcontrol.apiserver.k8s.io/v1beta2/flowschemas",
|
fmt.Sprintf("/apis/flowcontrol.apiserver.k8s.io/%s/flowschemas", flowSchemasVersion),
|
||||||
"/healthz":
|
"/healthz":
|
||||||
default:
|
default:
|
||||||
if !httpstream.IsUpgradeRequest(r) {
|
if !httpstream.IsUpgradeRequest(r) {
|
||||||
@ -736,8 +741,8 @@ func TestImpersonator(t *testing.T) {
|
|||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
|
|
||||||
case "/apis/flowcontrol.apiserver.k8s.io/v1beta2/prioritylevelconfigurations",
|
case fmt.Sprintf("/apis/flowcontrol.apiserver.k8s.io/%s/prioritylevelconfigurations", priorityLevelConfigurationsVersion),
|
||||||
"/apis/flowcontrol.apiserver.k8s.io/v1beta2/flowschemas":
|
fmt.Sprintf("/apis/flowcontrol.apiserver.k8s.io/%s/flowschemas", flowSchemasVersion):
|
||||||
// ignore requests related to priority and fairness logic
|
// ignore requests related to priority and fairness logic
|
||||||
require.Equal(t, http.MethodGet, r.Method)
|
require.Equal(t, http.MethodGet, r.Method)
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
@ -1051,7 +1056,11 @@ func TestImpersonator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestImpersonatorHTTPHandler(t *testing.T) {
|
func TestImpersonatorHTTPHandler(t *testing.T) {
|
||||||
const testUser = "test-user"
|
const (
|
||||||
|
testUser = "test-user"
|
||||||
|
priorityLevelConfigurationsVersion = "v1beta3"
|
||||||
|
flowSchemasVersion = "v1beta3"
|
||||||
|
)
|
||||||
|
|
||||||
testGroups := []string{"test-group-1", "test-group-2"}
|
testGroups := []string{"test-group-1", "test-group-2"}
|
||||||
testExtra := map[string][]string{
|
testExtra := map[string][]string{
|
||||||
@ -1149,7 +1158,9 @@ func TestImpersonatorHTTPHandler(t *testing.T) {
|
|||||||
Groups: testGroups,
|
Groups: testGroups,
|
||||||
Extra: testExtra,
|
Extra: testExtra,
|
||||||
}, nil, "")
|
}, nil, "")
|
||||||
ctx := audit.WithAuditContext(req.Context(), nil)
|
ctx := audit.WithAuditContext(req.Context())
|
||||||
|
ac := audit.AuditContextFrom(ctx)
|
||||||
|
ac.Event = nil
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
return req
|
return req
|
||||||
}(),
|
}(),
|
||||||
@ -1814,8 +1825,8 @@ func TestImpersonatorHTTPHandler(t *testing.T) {
|
|||||||
secure := ptls.Secure(rootCAs)
|
secure := ptls.Secure(rootCAs)
|
||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
case "/api/v1/namespaces/kube-system/configmaps",
|
case "/api/v1/namespaces/kube-system/configmaps",
|
||||||
"/apis/flowcontrol.apiserver.k8s.io/v1beta2/prioritylevelconfigurations",
|
fmt.Sprintf("/apis/flowcontrol.apiserver.k8s.io/%s/prioritylevelconfigurations", priorityLevelConfigurationsVersion),
|
||||||
"/apis/flowcontrol.apiserver.k8s.io/v1beta2/flowschemas",
|
fmt.Sprintf("/apis/flowcontrol.apiserver.k8s.io/%s/flowschemas", flowSchemasVersion),
|
||||||
"/healthz":
|
"/healthz":
|
||||||
default:
|
default:
|
||||||
if !httpstream.IsUpgradeRequest(r) {
|
if !httpstream.IsUpgradeRequest(r) {
|
||||||
@ -1925,7 +1936,9 @@ func newRequest(t *testing.T, h http.Header, userInfo user.Info, event *auditint
|
|||||||
if event != nil {
|
if event != nil {
|
||||||
ae = event
|
ae = event
|
||||||
}
|
}
|
||||||
ctx = audit.WithAuditContext(ctx, &audit.AuditContext{Event: ae})
|
ctx = audit.WithAuditContext(ctx)
|
||||||
|
ac := audit.AuditContextFrom(ctx)
|
||||||
|
ac.Event = ae
|
||||||
|
|
||||||
reqInfo := &request.RequestInfo{
|
reqInfo := &request.RequestInfo{
|
||||||
IsResourceRequest: false,
|
IsResourceRequest: false,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Package kubecertagent provides controllers that ensure a pod (the kube-cert-agent), is
|
// Package kubecertagent provides controllers that ensure a pod (the kube-cert-agent), is
|
||||||
@ -317,7 +317,7 @@ func (c *agentController) Sync(ctx controllerlib.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the certificate and key from the agent pod into our in-memory signer.
|
// Load the certificate and key from the agent pod into our in-memory signer.
|
||||||
if err := c.loadSigningKey(newestAgentPod); err != nil {
|
if err := c.loadSigningKey(ctx.Context, newestAgentPod); err != nil {
|
||||||
return c.failStrategyAndErr(ctx.Context, credIssuer, firstErr(depErr, err), configv1alpha1.CouldNotFetchKeyStrategyReason)
|
return c.failStrategyAndErr(ctx.Context, credIssuer, firstErr(depErr, err), configv1alpha1.CouldNotFetchKeyStrategyReason)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,14 +341,14 @@ func (c *agentController) Sync(ctx controllerlib.Context) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *agentController) loadSigningKey(agentPod *corev1.Pod) error {
|
func (c *agentController) loadSigningKey(ctx context.Context, agentPod *corev1.Pod) error {
|
||||||
// If we remember successfully loading the key from this pod recently, we can skip this step and return immediately.
|
// If we remember successfully loading the key from this pod recently, we can skip this step and return immediately.
|
||||||
if _, exists := c.execCache.Get(agentPod.UID); exists {
|
if _, exists := c.execCache.Get(agentPod.UID); exists {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec into the agent pod and cat out the certificate and the key.
|
// Exec into the agent pod and cat out the certificate and the key.
|
||||||
outputJSON, err := c.executor.Exec(agentPod.Namespace, agentPod.Name, "pinniped-concierge-kube-cert-agent", "print")
|
outputJSON, err := c.executor.Exec(ctx, agentPod.Namespace, agentPod.Name, "pinniped-concierge-kube-cert-agent", "print")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not exec into agent pod %s/%s: %w", agentPod.Namespace, agentPod.Name, err)
|
return fmt.Errorf("could not exec into agent pod %s/%s: %w", agentPod.Namespace, agentPod.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package kubecertagent
|
package kubecertagent
|
||||||
@ -229,7 +229,7 @@ func TestAgentController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mockExecSucceeds := func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
mockExecSucceeds := func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
||||||
executor.Exec("concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
executor.Exec(gomock.Any(), "concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
||||||
Return(`{"tls.crt": "dGVzdC1jZXJ0", "tls.key": "dGVzdC1rZXk="}`, nil) // "test-cert" / "test-key"
|
Return(`{"tls.crt": "dGVzdC1jZXJ0", "tls.key": "dGVzdC1rZXk="}`, nil) // "test-cert" / "test-key"
|
||||||
dynamicCert.SetCertKeyContent([]byte("test-cert"), []byte("test-key")).
|
dynamicCert.SetCertKeyContent([]byte("test-cert"), []byte("test-key")).
|
||||||
Return(nil)
|
Return(nil)
|
||||||
@ -740,7 +740,7 @@ func TestAgentController(t *testing.T) {
|
|||||||
validClusterInfoConfigMap,
|
validClusterInfoConfigMap,
|
||||||
},
|
},
|
||||||
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
||||||
executor.Exec("concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
executor.Exec(gomock.Any(), "concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
||||||
Return("", fmt.Errorf("some exec error")).
|
Return("", fmt.Errorf("some exec error")).
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
},
|
},
|
||||||
@ -769,7 +769,7 @@ func TestAgentController(t *testing.T) {
|
|||||||
validClusterInfoConfigMap,
|
validClusterInfoConfigMap,
|
||||||
},
|
},
|
||||||
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
||||||
executor.Exec("concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
executor.Exec(gomock.Any(), "concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
||||||
Return("bogus-data", nil).
|
Return("bogus-data", nil).
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
},
|
},
|
||||||
@ -798,7 +798,7 @@ func TestAgentController(t *testing.T) {
|
|||||||
validClusterInfoConfigMap,
|
validClusterInfoConfigMap,
|
||||||
},
|
},
|
||||||
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
||||||
executor.Exec("concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
executor.Exec(gomock.Any(), "concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
||||||
Return(`{"tls.crt": "invalid"}`, nil).
|
Return(`{"tls.crt": "invalid"}`, nil).
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
},
|
},
|
||||||
@ -827,7 +827,7 @@ func TestAgentController(t *testing.T) {
|
|||||||
validClusterInfoConfigMap,
|
validClusterInfoConfigMap,
|
||||||
},
|
},
|
||||||
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
||||||
executor.Exec("concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
executor.Exec(gomock.Any(), "concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
||||||
Return(`{"tls.crt": "dGVzdAo=", "tls.key": "invalid"}`, nil).
|
Return(`{"tls.crt": "dGVzdAo=", "tls.key": "invalid"}`, nil).
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
},
|
},
|
||||||
@ -856,7 +856,7 @@ func TestAgentController(t *testing.T) {
|
|||||||
validClusterInfoConfigMap,
|
validClusterInfoConfigMap,
|
||||||
},
|
},
|
||||||
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
mocks: func(t *testing.T, executor *mocks.MockPodCommandExecutorMockRecorder, dynamicCert *mocks.MockDynamicCertPrivateMockRecorder, execCache *cache.Expiring) {
|
||||||
executor.Exec("concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
executor.Exec(gomock.Any(), "concierge", "pinniped-concierge-kube-cert-agent-xyz-1234", "pinniped-concierge-kube-cert-agent", "print").
|
||||||
Return(`{"tls.crt": "dGVzdC1jZXJ0", "tls.key": "dGVzdC1rZXk="}`, nil). // "test-cert" / "test-key"
|
Return(`{"tls.crt": "dGVzdC1jZXJ0", "tls.key": "dGVzdC1rZXk="}`, nil). // "test-cert" / "test-key"
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
dynamicCert.SetCertKeyContent([]byte("test-cert"), []byte("test-key")).
|
dynamicCert.SetCertKeyContent([]byte("test-cert"), []byte("test-key")).
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
package mocks
|
package mocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
context "context"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
|
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
@ -38,10 +39,10 @@ func (m *MockPodCommandExecutor) EXPECT() *MockPodCommandExecutorMockRecorder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exec mocks base method.
|
// Exec mocks base method.
|
||||||
func (m *MockPodCommandExecutor) Exec(arg0, arg1 string, arg2 ...string) (string, error) {
|
func (m *MockPodCommandExecutor) Exec(arg0 context.Context, arg1, arg2 string, arg3 ...string) (string, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
varargs := []interface{}{arg0, arg1}
|
varargs := []interface{}{arg0, arg1, arg2}
|
||||||
for _, a := range arg2 {
|
for _, a := range arg3 {
|
||||||
varargs = append(varargs, a)
|
varargs = append(varargs, a)
|
||||||
}
|
}
|
||||||
ret := m.ctrl.Call(m, "Exec", varargs...)
|
ret := m.ctrl.Call(m, "Exec", varargs...)
|
||||||
@ -51,8 +52,8 @@ func (m *MockPodCommandExecutor) Exec(arg0, arg1 string, arg2 ...string) (string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exec indicates an expected call of Exec.
|
// Exec indicates an expected call of Exec.
|
||||||
func (mr *MockPodCommandExecutorMockRecorder) Exec(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
func (mr *MockPodCommandExecutorMockRecorder) Exec(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockPodCommandExecutor)(nil).Exec), varargs...)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockPodCommandExecutor)(nil).Exec), varargs...)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package kubecertagent
|
package kubecertagent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
@ -15,7 +16,7 @@ import (
|
|||||||
|
|
||||||
// PodCommandExecutor can exec a command in a pod located via namespace and name.
|
// PodCommandExecutor can exec a command in a pod located via namespace and name.
|
||||||
type PodCommandExecutor interface {
|
type PodCommandExecutor interface {
|
||||||
Exec(podNamespace string, podName string, commandAndArgs ...string) (stdoutResult string, err error)
|
Exec(ctx context.Context, podNamespace string, podName string, commandAndArgs ...string) (stdoutResult string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type kubeClientPodCommandExecutor struct {
|
type kubeClientPodCommandExecutor struct {
|
||||||
@ -31,8 +32,7 @@ func NewPodCommandExecutor(kubeConfig *restclient.Config, kubeClient kubernetes.
|
|||||||
return &kubeClientPodCommandExecutor{kubeConfig: kubeConfig, kubeClient: kubeClient}
|
return &kubeClientPodCommandExecutor{kubeConfig: kubeConfig, kubeClient: kubeClient}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *kubeClientPodCommandExecutor) Exec(podNamespace string, podName string, commandAndArgs ...string) (string, error) {
|
func (s *kubeClientPodCommandExecutor) Exec(ctx context.Context, podNamespace string, podName string, commandAndArgs ...string) (string, error) {
|
||||||
// TODO: see if we can add a timeout or make this cancelable somehow
|
|
||||||
request := s.kubeClient.
|
request := s.kubeClient.
|
||||||
CoreV1().
|
CoreV1().
|
||||||
RESTClient().
|
RESTClient().
|
||||||
@ -55,7 +55,7 @@ func (s *kubeClientPodCommandExecutor) Exec(podNamespace string, podName string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
var stdoutBuf bytes.Buffer
|
var stdoutBuf bytes.Buffer
|
||||||
if err := executor.Stream(remotecommand.StreamOptions{Stdout: &stdoutBuf}); err != nil {
|
if err := executor.StreamWithContext(ctx, remotecommand.StreamOptions{Stdout: &stdoutBuf}); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return stdoutBuf.String(), nil
|
return stdoutBuf.String(), nil
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package kubecertagent
|
package kubecertagent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ func TestSecureTLS(t *testing.T) {
|
|||||||
// build this exactly like our production could does
|
// build this exactly like our production could does
|
||||||
podCommandExecutor := NewPodCommandExecutor(client.JSONConfig, client.Kubernetes)
|
podCommandExecutor := NewPodCommandExecutor(client.JSONConfig, client.Kubernetes)
|
||||||
|
|
||||||
got, err := podCommandExecutor.Exec("podNamespace", "podName", "command", "arg1", "arg2")
|
got, err := podCommandExecutor.Exec(context.Background(), "podNamespace", "podName", "command", "arg1", "arg2")
|
||||||
require.Equal(t, &errors.StatusError{}, err)
|
require.Equal(t, &errors.StatusError{}, err)
|
||||||
require.Empty(t, got)
|
require.Empty(t, got)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package controllerlib
|
package controllerlib
|
||||||
@ -59,7 +59,7 @@ func WithInformer(getter InformerGetter, filter Filter, opt InformerOption) Opti
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
_, err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
object := metaOrDie(obj)
|
object := metaOrDie(obj)
|
||||||
if filter.Add(object) {
|
if filter.Add(object) {
|
||||||
@ -113,6 +113,10 @@ func WithInformer(getter InformerGetter, filter Filter, opt InformerOption) Opti
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
// Shouldn't really happen.
|
||||||
|
panic(die(fmt.Sprintf("got error from AddEventHandler: %s", err.Error())))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package kubeclient
|
package kubeclient
|
||||||
@ -974,21 +974,6 @@ func TestUnwrap(t *testing.T) {
|
|||||||
testUnwrap(t, execClient, serverSubjects)
|
testUnwrap(t, execClient, serverSubjects)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("gcp client", func(t *testing.T) {
|
|
||||||
t.Parallel() // make sure to run in parallel to confirm that our client-go TLS cache busting works (i.e. assert no data races)
|
|
||||||
|
|
||||||
gcpClient := makeClient(t, restConfig, func(config *rest.Config) {
|
|
||||||
config.AuthProvider = &clientcmdapi.AuthProviderConfig{
|
|
||||||
Name: "gcp",
|
|
||||||
Config: map[string]string{
|
|
||||||
"cmd-path": `echo {"access_token":"fake","token_expiry":"2200-01-02T15:04:05.999999999Z07:00"}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
testUnwrap(t, gcpClient, serverSubjects)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("oidc client", func(t *testing.T) {
|
t.Run("oidc client", func(t *testing.T) {
|
||||||
t.Parallel() // make sure to run in parallel to confirm that our client-go TLS cache busting works (i.e. assert no data races)
|
t.Parallel() // make sure to run in parallel to confirm that our client-go TLS cache busting works (i.e. assert no data races)
|
||||||
|
|
||||||
@ -1004,23 +989,6 @@ func TestUnwrap(t *testing.T) {
|
|||||||
|
|
||||||
testUnwrap(t, oidcClient, serverSubjects)
|
testUnwrap(t, oidcClient, serverSubjects)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("azure client", func(t *testing.T) {
|
|
||||||
t.Parallel() // make sure to run in parallel to confirm that our client-go TLS cache busting works (i.e. assert no data races)
|
|
||||||
|
|
||||||
azureClient := makeClient(t, restConfig, func(config *rest.Config) {
|
|
||||||
config.AuthProvider = &clientcmdapi.AuthProviderConfig{
|
|
||||||
Name: "azure",
|
|
||||||
Config: map[string]string{
|
|
||||||
"client-id": "pinny",
|
|
||||||
"tenant-id": "danger",
|
|
||||||
"apiserver-id": "1234",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
testUnwrap(t, azureClient, serverSubjects)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUnwrap(t *testing.T, client *Client, serverSubjects [][]byte) {
|
func testUnwrap(t *testing.T, client *Client, serverSubjects [][]byte) {
|
||||||
|
70
internal/psets/psets.go
Normal file
70
internal/psets/psets.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package psets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These were copied from https://github.com/kubernetes/kubernetes/tree/v1.25.5/staging/src/k8s.io/apimachinery/pkg/util/sets
|
||||||
|
// which is the last version before they were converted to generic functions which require the use
|
||||||
|
// of Go 1.18+ to compile. This is not a full copy of the files from k/k, but rather only copies of the
|
||||||
|
// functions that we actually use. When we are ready to require the use of Go 1.18+ to compile Pinniped,
|
||||||
|
// then we can go back to using the version of this package from the k8s libraries. Our use
|
||||||
|
// of this package was very minimal, so its easy enough to just copy the few functions that we were
|
||||||
|
// actually using to keep Go 1.17 compatibility a little longer.
|
||||||
|
|
||||||
|
// Empty is public since it is used by some internal API objects for conversions between external
|
||||||
|
// string arrays and internal sets, and conversion logic requires public types today.
|
||||||
|
type Empty struct{}
|
||||||
|
|
||||||
|
// sets.String is a set of strings, implemented via map[string]struct{} for minimal memory consumption.
|
||||||
|
type String map[string]Empty
|
||||||
|
|
||||||
|
// StringKeySet creates a String from a keys of a map[string](? extends interface{}).
|
||||||
|
// If the value passed in is not actually a map, this will panic.
|
||||||
|
func StringKeySet(theMap interface{}) String {
|
||||||
|
v := reflect.ValueOf(theMap)
|
||||||
|
ret := String{}
|
||||||
|
|
||||||
|
for _, keyValue := range v.MapKeys() {
|
||||||
|
ret.Insert(keyValue.Interface().(string))
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert adds items to the set.
|
||||||
|
func (s String) Insert(items ...string) String {
|
||||||
|
for _, item := range items {
|
||||||
|
s[item] = Empty{}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has returns true if and only if item is contained in the set.
|
||||||
|
func (s String) Has(item string) bool {
|
||||||
|
_, contained := s[item]
|
||||||
|
return contained
|
||||||
|
}
|
||||||
|
|
||||||
|
type sortableSliceOfString []string
|
||||||
|
|
||||||
|
func (s sortableSliceOfString) Len() int { return len(s) }
|
||||||
|
func (s sortableSliceOfString) Less(i, j int) bool { return lessString(s[i], s[j]) }
|
||||||
|
func (s sortableSliceOfString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
|
// List returns the contents as a sorted string slice.
|
||||||
|
func (s String) List() []string {
|
||||||
|
res := make(sortableSliceOfString, 0, len(s))
|
||||||
|
for key := range s {
|
||||||
|
res = append(res, key)
|
||||||
|
}
|
||||||
|
sort.Sort(res)
|
||||||
|
return []string(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lessString(lhs, rhs string) bool {
|
||||||
|
return lhs < rhs
|
||||||
|
}
|
@ -18,12 +18,12 @@ import (
|
|||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
|
||||||
|
|
||||||
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
|
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
|
||||||
"go.pinniped.dev/internal/httputil/httperr"
|
"go.pinniped.dev/internal/httputil/httperr"
|
||||||
"go.pinniped.dev/internal/oidc/provider"
|
"go.pinniped.dev/internal/oidc/provider"
|
||||||
"go.pinniped.dev/internal/plog"
|
"go.pinniped.dev/internal/plog"
|
||||||
|
"go.pinniped.dev/internal/psets"
|
||||||
"go.pinniped.dev/pkg/oidcclient/nonce"
|
"go.pinniped.dev/pkg/oidcclient/nonce"
|
||||||
"go.pinniped.dev/pkg/oidcclient/oidctypes"
|
"go.pinniped.dev/pkg/oidcclient/oidctypes"
|
||||||
"go.pinniped.dev/pkg/oidcclient/pkce"
|
"go.pinniped.dev/pkg/oidcclient/pkce"
|
||||||
@ -421,7 +421,7 @@ func maybeLogClaims(msg, name string, claims map[string]interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if plog.Enabled(plog.LevelDebug) { // log keys at debug level
|
if plog.Enabled(plog.LevelDebug) { // log keys at debug level
|
||||||
keys := sets.StringKeySet(claims).List() // note: this is only safe because the compiler asserts that claims is a map[string]<anything>
|
keys := psets.StringKeySet(claims).List() // note: this is only safe because the compiler asserts that claims is a map[string]<anything>
|
||||||
plog.Debug(msg, "providerName", name, "keys", keys)
|
plog.Debug(msg, "providerName", name, "keys", keys)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package integration
|
package integration
|
||||||
@ -17,13 +17,13 @@ import (
|
|||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/rand"
|
"k8s.io/apimachinery/pkg/util/rand"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
|
||||||
"k8s.io/client-go/util/retry"
|
"k8s.io/client-go/util/retry"
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
|
|
||||||
"go.pinniped.dev/internal/downward"
|
"go.pinniped.dev/internal/downward"
|
||||||
"go.pinniped.dev/internal/kubeclient"
|
"go.pinniped.dev/internal/kubeclient"
|
||||||
"go.pinniped.dev/internal/leaderelection"
|
"go.pinniped.dev/internal/leaderelection"
|
||||||
|
"go.pinniped.dev/internal/psets"
|
||||||
"go.pinniped.dev/test/testlib"
|
"go.pinniped.dev/test/testlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ func leaderElectionClients(t *testing.T, namespace *corev1.Namespace, leaseName
|
|||||||
clients[identity], cancels[identity] = leaderElectionClient(t, namespace, leaseName, identity)
|
clients[identity], cancels[identity] = leaderElectionClient(t, namespace, leaseName, identity)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("running leader election client tests with %d clients: %v", len(clients), sets.StringKeySet(clients).List())
|
t.Logf("running leader election client tests with %d clients: %v", len(clients), psets.StringKeySet(clients).List())
|
||||||
|
|
||||||
return clients, cancels
|
return clients, cancels
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ func pickRandomLeaderElectionClient(clients map[string]*kubeclient.Client) *kube
|
|||||||
func waitForIdentity(ctx context.Context, t *testing.T, namespace *corev1.Namespace, leaseName string, clients map[string]*kubeclient.Client) *coordinationv1.Lease {
|
func waitForIdentity(ctx context.Context, t *testing.T, namespace *corev1.Namespace, leaseName string, clients map[string]*kubeclient.Client) *coordinationv1.Lease {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
identities := sets.StringKeySet(clients)
|
identities := psets.StringKeySet(clients)
|
||||||
var out *coordinationv1.Lease
|
var out *coordinationv1.Lease
|
||||||
|
|
||||||
testlib.RequireEventuallyWithoutError(t, func() (bool, error) {
|
testlib.RequireEventuallyWithoutError(t, func() (bool, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user