Merge pull request #104483 from margocrawf/master

Add UID to client-go impersonation config

Kubernetes-commit: 48d844ec64bd83a378418d420ba455fa28043cbc
This commit is contained in:
Kubernetes Publisher 2021-09-27 07:33:36 -07:00
commit 372575c38a
8 changed files with 50 additions and 7 deletions

4
go.mod
View File

@ -30,7 +30,7 @@ require (
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
google.golang.org/protobuf v1.26.0
k8s.io/api v0.0.0-20210917114730-87c4113e35a1
k8s.io/api v0.0.0-20210924234029-7036ead25397
k8s.io/apimachinery v0.0.0-20210920194645-86c0c0f8c8e2
k8s.io/klog/v2 v2.20.0
k8s.io/kube-openapi v0.0.0-20210817084001-7fbd8d59e5b8
@ -40,6 +40,6 @@ require (
)
replace (
k8s.io/api => k8s.io/api v0.0.0-20210917114730-87c4113e35a1
k8s.io/api => k8s.io/api v0.0.0-20210924234029-7036ead25397
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20210920194645-86c0c0f8c8e2
)

4
go.sum
View File

@ -599,8 +599,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.0.0-20210917114730-87c4113e35a1 h1:c5smJttDF8/Ols66NZM4olxSwIEa3p0fklSgV9WA9K8=
k8s.io/api v0.0.0-20210917114730-87c4113e35a1/go.mod h1:NPiqbLN26Y6vkL9V/SbA6NtBMKgFkdVKnh5Drj9GgMo=
k8s.io/api v0.0.0-20210924234029-7036ead25397 h1:JaNZFi1NkZWSkzbQbOhR5JIH9zCUY3ANkqoKIAGLyiI=
k8s.io/api v0.0.0-20210924234029-7036ead25397/go.mod h1:wyj7UIiindRSrWpl4OJqfk8C2m/1vxi8wpf9x8RwQMQ=
k8s.io/apimachinery v0.0.0-20210920194645-86c0c0f8c8e2 h1:MdB81XVh3V0ZnRKsg6KRpVSH90nw2XjN9JcK9NIWY7Q=
k8s.io/apimachinery v0.0.0-20210920194645-86c0c0f8c8e2/go.mod h1:CimYO7ypGwnQeTeoJQ8Jht0OVH2glTFHGy7xEhLj3sk=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=

View File

@ -202,6 +202,8 @@ func (c *Config) String() string {
type ImpersonationConfig struct {
// UserName is the username to impersonate on each request.
UserName string
// UID is a unique value that identifies the user.
UID string
// Groups are the groups to impersonate on each request.
Groups []string
// Extra is a free-form field which can be used to link some authentication information
@ -608,9 +610,10 @@ func CopyConfig(config *Config) *Config {
BearerToken: config.BearerToken,
BearerTokenFile: config.BearerTokenFile,
Impersonate: ImpersonationConfig{
UserName: config.Impersonate.UserName,
UID: config.Impersonate.UID,
Groups: config.Impersonate.Groups,
Extra: config.Impersonate.Extra,
UserName: config.Impersonate.UserName,
},
AuthProvider: config.AuthProvider,
AuthConfigPersister: config.AuthConfigPersister,

View File

@ -594,6 +594,7 @@ func TestConfigSprint(t *testing.T) {
BearerToken: "1234567890",
Impersonate: ImpersonationConfig{
UserName: "gopher2",
UID: "uid123",
},
AuthProvider: &clientcmdapi.AuthProviderConfig{
Name: "gopher",
@ -626,7 +627,7 @@ func TestConfigSprint(t *testing.T) {
Proxy: fakeProxyFunc,
}
want := fmt.Sprintf(
`&rest.Config{Host:"localhost:8080", APIPath:"v1", ContentConfig:rest.ContentConfig{AcceptContentTypes:"application/json", ContentType:"application/json", GroupVersion:(*schema.GroupVersion)(nil), NegotiatedSerializer:runtime.NegotiatedSerializer(nil)}, Username:"gopher", Password:"--- REDACTED ---", BearerToken:"--- REDACTED ---", BearerTokenFile:"", Impersonate:rest.ImpersonationConfig{UserName:"gopher2", Groups:[]string(nil), Extra:map[string][]string(nil)}, AuthProvider:api.AuthProviderConfig{Name: "gopher", Config: map[string]string{--- REDACTED ---}}, AuthConfigPersister:rest.AuthProviderConfigPersister(--- REDACTED ---), ExecProvider:api.ExecConfig{Command: "sudo", Args: []string{"--- REDACTED ---"}, Env: []ExecEnvVar{--- REDACTED ---}, APIVersion: "", ProvideClusterInfo: true, Config: runtime.Object(--- REDACTED ---), StdinUnavailable: false}, TLSClientConfig:rest.sanitizedTLSClientConfig{Insecure:false, ServerName:"", CertFile:"a.crt", KeyFile:"a.key", CAFile:"", CertData:[]uint8{0x2d, 0x2d, 0x2d, 0x20, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x41, 0x54, 0x45, 0x44, 0x20, 0x2d, 0x2d, 0x2d}, KeyData:[]uint8{0x2d, 0x2d, 0x2d, 0x20, 0x52, 0x45, 0x44, 0x41, 0x43, 0x54, 0x45, 0x44, 0x20, 0x2d, 0x2d, 0x2d}, CAData:[]uint8(nil), NextProtos:[]string{"h2", "http/1.1"}}, UserAgent:"gobot", DisableCompression:false, Transport:(*rest.fakeRoundTripper)(%p), WrapTransport:(transport.WrapperFunc)(%p), QPS:1, Burst:2, RateLimiter:(*rest.fakeLimiter)(%p), WarningHandler:rest.fakeWarningHandler{}, Timeout:3000000000, Dial:(func(context.Context, string, string) (net.Conn, error))(%p), Proxy:(func(*http.Request) (*url.URL, error))(%p)}`,
`&rest.Config{Host:"localhost:8080", APIPath:"v1", ContentConfig:rest.ContentConfig{AcceptContentTypes:"application/json", ContentType:"application/json", GroupVersion:(*schema.GroupVersion)(nil), NegotiatedSerializer:runtime.NegotiatedSerializer(nil)}, Username:"gopher", Password:"--- REDACTED ---", BearerToken:"--- REDACTED ---", BearerTokenFile:"", Impersonate:rest.ImpersonationConfig{UserName:"gopher2", UID:"uid123", Groups:[]string(nil), Extra:map[string][]string(nil)}, AuthProvider:api.AuthProviderConfig{Name: "gopher", Config: map[string]string{--- REDACTED ---}}, AuthConfigPersister:rest.AuthProviderConfigPersister(--- REDACTED ---), ExecProvider:api.ExecConfig{Command: "sudo", Args: []string{"--- REDACTED ---"}, Env: []ExecEnvVar{--- REDACTED ---}, APIVersion: "", ProvideClusterInfo: true, Config: runtime.Object(--- REDACTED ---), StdinUnavailable: false}, TLSClientConfig:rest.sanitizedTLSClientConfig{Insecure:false, ServerName:"", CertFile:"a.crt", KeyFile:"a.key", CAFile:"", CertData:[]uint8{0x2d, 0x2d, 0x2d, 0x20, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x41, 0x54, 0x45, 0x44, 0x20, 0x2d, 0x2d, 0x2d}, KeyData:[]uint8{0x2d, 0x2d, 0x2d, 0x20, 0x52, 0x45, 0x44, 0x41, 0x43, 0x54, 0x45, 0x44, 0x20, 0x2d, 0x2d, 0x2d}, CAData:[]uint8(nil), NextProtos:[]string{"h2", "http/1.1"}}, UserAgent:"gobot", DisableCompression:false, Transport:(*rest.fakeRoundTripper)(%p), WrapTransport:(transport.WrapperFunc)(%p), QPS:1, Burst:2, RateLimiter:(*rest.fakeLimiter)(%p), WarningHandler:rest.fakeWarningHandler{}, Timeout:3000000000, Dial:(func(context.Context, string, string) (net.Conn, error))(%p), Proxy:(func(*http.Request) (*url.URL, error))(%p)}`,
c.Transport, fakeWrapperFunc, c.RateLimiter, fakeDialFunc, fakeProxyFunc,
)

View File

@ -83,6 +83,7 @@ func (c *Config) TransportConfig() (*transport.Config, error) {
BearerTokenFile: c.BearerTokenFile,
Impersonate: transport.ImpersonationConfig{
UserName: c.Impersonate.UserName,
UID: c.Impersonate.UID,
Groups: c.Impersonate.Groups,
Extra: c.Impersonate.Extra,
},

View File

@ -82,6 +82,8 @@ type Config struct {
type ImpersonationConfig struct {
// UserName matches user.Info.GetName()
UserName string
// UID matches user.Info.GetUID()
UID string
// Groups matches user.Info.GetGroups()
Groups []string
// Extra matches user.Info.GetExtra()

View File

@ -57,6 +57,7 @@ func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTrip
rt = NewUserAgentRoundTripper(config.UserAgent, rt)
}
if len(config.Impersonate.UserName) > 0 ||
len(config.Impersonate.UID) > 0 ||
len(config.Impersonate.Groups) > 0 ||
len(config.Impersonate.Extra) > 0 {
rt = NewImpersonatingRoundTripper(config.Impersonate, rt)
@ -199,6 +200,9 @@ const (
// ImpersonateUserHeader is used to impersonate a particular user during an API server request
ImpersonateUserHeader = "Impersonate-User"
// ImpersonateUIDHeader is used to impersonate a particular UID during an API server request
ImpersonateUIDHeader = "Impersonate-Uid"
// ImpersonateGroupHeader is used to impersonate a particular group during an API server request.
// It can be repeated multiplied times for multiple groups.
ImpersonateGroupHeader = "Impersonate-Group"
@ -230,7 +234,9 @@ func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Respons
}
req = utilnet.CloneRequest(req)
req.Header.Set(ImpersonateUserHeader, rt.impersonate.UserName)
if rt.impersonate.UID != "" {
req.Header.Set(ImpersonateUIDHeader, rt.impersonate.UID)
}
for _, group := range rt.impersonate.Groups {
req.Header.Add(ImpersonateGroupHeader, group)
}

View File

@ -200,6 +200,25 @@ func TestImpersonationRoundTripper(t *testing.T) {
}{
{
name: "all",
impersonationConfig: ImpersonationConfig{
UserName: "user",
UID: "uid-a",
Groups: []string{"one", "two"},
Extra: map[string][]string{
"first": {"A", "a"},
"second": {"B", "b"},
},
},
expected: map[string][]string{
ImpersonateUserHeader: {"user"},
ImpersonateUIDHeader: {"uid-a"},
ImpersonateGroupHeader: {"one", "two"},
ImpersonateUserExtraHeaderPrefix + "First": {"A", "a"},
ImpersonateUserExtraHeaderPrefix + "Second": {"B", "b"},
},
},
{
name: "username, groups and extra",
impersonationConfig: ImpersonationConfig{
UserName: "user",
Groups: []string{"one", "two"},
@ -215,6 +234,17 @@ func TestImpersonationRoundTripper(t *testing.T) {
ImpersonateUserExtraHeaderPrefix + "Second": {"B", "b"},
},
},
{
name: "username and uid",
impersonationConfig: ImpersonationConfig{
UserName: "user",
UID: "uid-a",
},
expected: map[string][]string{
ImpersonateUserHeader: {"user"},
ImpersonateUIDHeader: {"uid-a"},
},
},
{
name: "escape handling",
impersonationConfig: ImpersonationConfig{