Merge pull request #62692 from mikedanese/trev2

authn: extend authenticator.Token to support audience validation
This commit is contained in:
k8s-ci-robot 2018-11-16 20:27:25 -08:00 committed by GitHub
commit f38cc95505
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 758 additions and 161 deletions

View File

@ -80871,6 +80871,13 @@
"io.k8s.api.authentication.v1.TokenReviewSpec": { "io.k8s.api.authentication.v1.TokenReviewSpec": {
"description": "TokenReviewSpec is a description of the token authentication request.", "description": "TokenReviewSpec is a description of the token authentication request.",
"properties": { "properties": {
"audiences": {
"description": "Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver.",
"type": "array",
"items": {
"type": "string"
}
},
"token": { "token": {
"description": "Token is the opaque bearer token.", "description": "Token is the opaque bearer token.",
"type": "string" "type": "string"
@ -80880,6 +80887,13 @@
"io.k8s.api.authentication.v1.TokenReviewStatus": { "io.k8s.api.authentication.v1.TokenReviewStatus": {
"description": "TokenReviewStatus is the result of the token authentication request.", "description": "TokenReviewStatus is the result of the token authentication request.",
"properties": { "properties": {
"audiences": {
"description": "Audiences are audience identifiers chosen by the authenticator that are compatible with both the TokenReview and token. An identifier is any identifier in the intersection of the TokenReviewSpec audiences and the token's audiences. A client of the TokenReview API that sets the spec.audiences field should validate that a compatible audience identifier is returned in the status.audiences field to ensure that the TokenReview server is audience aware. If a TokenReview returns an empty status.audience field where status.authenticated is \"true\", the token is valid against the audience of the Kubernetes API server.",
"type": "array",
"items": {
"type": "string"
}
},
"authenticated": { "authenticated": {
"description": "Authenticated indicates that the token was associated with a known user.", "description": "Authenticated indicates that the token was associated with a known user.",
"type": "boolean" "type": "boolean"
@ -80961,6 +80975,13 @@
"io.k8s.api.authentication.v1beta1.TokenReviewSpec": { "io.k8s.api.authentication.v1beta1.TokenReviewSpec": {
"description": "TokenReviewSpec is a description of the token authentication request.", "description": "TokenReviewSpec is a description of the token authentication request.",
"properties": { "properties": {
"audiences": {
"description": "Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver.",
"type": "array",
"items": {
"type": "string"
}
},
"token": { "token": {
"description": "Token is the opaque bearer token.", "description": "Token is the opaque bearer token.",
"type": "string" "type": "string"
@ -80970,6 +80991,13 @@
"io.k8s.api.authentication.v1beta1.TokenReviewStatus": { "io.k8s.api.authentication.v1beta1.TokenReviewStatus": {
"description": "TokenReviewStatus is the result of the token authentication request.", "description": "TokenReviewStatus is the result of the token authentication request.",
"properties": { "properties": {
"audiences": {
"description": "Audiences are audience identifiers chosen by the authenticator that are compatible with both the TokenReview and token. An identifier is any identifier in the intersection of the TokenReviewSpec audiences and the token's audiences. A client of the TokenReview API that sets the spec.audiences field should validate that a compatible audience identifier is returned in the status.audiences field to ensure that the TokenReview server is audience aware. If a TokenReview returns an empty status.audience field where status.authenticated is \"true\", the token is valid against the audience of the Kubernetes API server.",
"type": "array",
"items": {
"type": "string"
}
},
"authenticated": { "authenticated": {
"description": "Authenticated indicates that the token was associated with a known user.", "description": "Authenticated indicates that the token was associated with a known user.",
"type": "boolean" "type": "boolean"

View File

@ -395,6 +395,13 @@
"token": { "token": {
"type": "string", "type": "string",
"description": "Token is the opaque bearer token." "description": "Token is the opaque bearer token."
},
"audiences": {
"type": "array",
"items": {
"type": "string"
},
"description": "Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver."
} }
} }
}, },
@ -410,6 +417,13 @@
"$ref": "v1.UserInfo", "$ref": "v1.UserInfo",
"description": "User is the UserInfo associated with the provided token." "description": "User is the UserInfo associated with the provided token."
}, },
"audiences": {
"type": "array",
"items": {
"type": "string"
},
"description": "Audiences are audience identifiers chosen by the authenticator that are compatible with both the TokenReview and token. An identifier is any identifier in the intersection of the TokenReviewSpec audiences and the token's audiences. A client of the TokenReview API that sets the spec.audiences field should validate that a compatible audience identifier is returned in the status.audiences field to ensure that the TokenReview server is audience aware. If a TokenReview returns an empty status.audience field where status.authenticated is \"true\", the token is valid against the audience of the Kubernetes API server."
},
"error": { "error": {
"type": "string", "type": "string",
"description": "Error indicates that the token couldn't be checked" "description": "Error indicates that the token couldn't be checked"

View File

@ -395,6 +395,13 @@
"token": { "token": {
"type": "string", "type": "string",
"description": "Token is the opaque bearer token." "description": "Token is the opaque bearer token."
},
"audiences": {
"type": "array",
"items": {
"type": "string"
},
"description": "Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver."
} }
} }
}, },
@ -410,6 +417,13 @@
"$ref": "v1beta1.UserInfo", "$ref": "v1beta1.UserInfo",
"description": "User is the UserInfo associated with the provided token." "description": "User is the UserInfo associated with the provided token."
}, },
"audiences": {
"type": "array",
"items": {
"type": "string"
},
"description": "Audiences are audience identifiers chosen by the authenticator that are compatible with both the TokenReview and token. An identifier is any identifier in the intersection of the TokenReviewSpec audiences and the token's audiences. A client of the TokenReview API that sets the spec.audiences field should validate that a compatible audience identifier is returned in the status.audiences field to ensure that the TokenReview server is audience aware. If a TokenReview returns an empty status.audience field where status.authenticated is \"true\", the token is valid against the audience of the Kubernetes API server."
},
"error": { "error": {
"type": "string", "type": "string",
"description": "Error indicates that the token couldn't be checked" "description": "Error indicates that the token couldn't be checked"

View File

@ -1053,6 +1053,13 @@ When an object is created, the system will populate this list with the current s
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>
</tr> </tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">audiences</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody> </tbody>
</table> </table>
@ -1095,6 +1102,13 @@ When an object is created, the system will populate this list with the current s
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">audiences</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Audiences are audience identifiers chosen by the authenticator that are compatible with both the TokenReview and token. An identifier is any identifier in the intersection of the TokenReviewSpec audiences and the token&#8217;s audiences. A client of the TokenReview API that sets the spec.audiences field should validate that a compatible audience identifier is returned in the status.audiences field to ensure that the TokenReview server is audience aware. If a TokenReview returns an empty status.audience field where status.authenticated is "true", the token is valid against the audience of the Kubernetes API server.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">error</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">error</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Error indicates that the token couldn&#8217;t be checked</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Error indicates that the token couldn&#8217;t be checked</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>

View File

@ -567,6 +567,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>
</tr> </tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">audiences</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody> </tbody>
</table> </table>
@ -1060,6 +1067,13 @@ When an object is created, the system will populate this list with the current s
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">audiences</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Audiences are audience identifiers chosen by the authenticator that are compatible with both the TokenReview and token. An identifier is any identifier in the intersection of the TokenReviewSpec audiences and the token&#8217;s audiences. A client of the TokenReview API that sets the spec.audiences field should validate that a compatible audience identifier is returned in the status.audiences field to ensure that the TokenReview server is audience aware. If a TokenReview returns an empty status.audience field where status.authenticated is "true", the token is valid against the audience of the Kubernetes API server.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">error</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">error</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Error indicates that the token couldn&#8217;t be checked</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Error indicates that the token couldn&#8217;t be checked</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>

View File

@ -59,6 +59,12 @@ type TokenReview struct {
type TokenReviewSpec struct { type TokenReviewSpec struct {
// Token is the opaque bearer token. // Token is the opaque bearer token.
Token string Token string
// Audiences is a list of the identifiers that the resource server presented
// with the token identifies as. Audience-aware token authenticators will
// verify that the token was intended for at least one of the audiences in
// this list. If no audiences are provided, the audience will default to the
// audience of the Kubernetes apiserver.
Audiences []string
} }
// TokenReviewStatus is the result of the token authentication request. // TokenReviewStatus is the result of the token authentication request.
@ -68,6 +74,16 @@ type TokenReviewStatus struct {
Authenticated bool Authenticated bool
// User is the UserInfo associated with the provided token. // User is the UserInfo associated with the provided token.
User UserInfo User UserInfo
// Audiences are audience identifiers chosen by the authenticator that are
// compatible with both the TokenReview and token. An identifier is any
// identifier in the intersection of the TokenReviewSpec audiences and the
// token's audiences. A client of the TokenReview API that sets the
// spec.audiences field should validate that a compatible audience identifier
// is returned in the status.audiences field to ensure that the TokenReview
// server is audience aware. If a TokenReview returns an empty
// status.audience field where status.authenticated is "true", the token is
// valid against the audience of the Kubernetes API server.
Audiences []string
// Error indicates that the token couldn't be checked // Error indicates that the token couldn't be checked
Error string Error string
} }

View File

@ -263,6 +263,7 @@ func Convert_authentication_TokenReview_To_v1_TokenReview(in *authentication.Tok
func autoConvert_v1_TokenReviewSpec_To_authentication_TokenReviewSpec(in *v1.TokenReviewSpec, out *authentication.TokenReviewSpec, s conversion.Scope) error { func autoConvert_v1_TokenReviewSpec_To_authentication_TokenReviewSpec(in *v1.TokenReviewSpec, out *authentication.TokenReviewSpec, s conversion.Scope) error {
out.Token = in.Token out.Token = in.Token
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
return nil return nil
} }
@ -273,6 +274,7 @@ func Convert_v1_TokenReviewSpec_To_authentication_TokenReviewSpec(in *v1.TokenRe
func autoConvert_authentication_TokenReviewSpec_To_v1_TokenReviewSpec(in *authentication.TokenReviewSpec, out *v1.TokenReviewSpec, s conversion.Scope) error { func autoConvert_authentication_TokenReviewSpec_To_v1_TokenReviewSpec(in *authentication.TokenReviewSpec, out *v1.TokenReviewSpec, s conversion.Scope) error {
out.Token = in.Token out.Token = in.Token
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
return nil return nil
} }
@ -286,6 +288,7 @@ func autoConvert_v1_TokenReviewStatus_To_authentication_TokenReviewStatus(in *v1
if err := Convert_v1_UserInfo_To_authentication_UserInfo(&in.User, &out.User, s); err != nil { if err := Convert_v1_UserInfo_To_authentication_UserInfo(&in.User, &out.User, s); err != nil {
return err return err
} }
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
out.Error = in.Error out.Error = in.Error
return nil return nil
} }
@ -300,6 +303,7 @@ func autoConvert_authentication_TokenReviewStatus_To_v1_TokenReviewStatus(in *au
if err := Convert_authentication_UserInfo_To_v1_UserInfo(&in.User, &out.User, s); err != nil { if err := Convert_authentication_UserInfo_To_v1_UserInfo(&in.User, &out.User, s); err != nil {
return err return err
} }
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
out.Error = in.Error out.Error = in.Error
return nil return nil
} }

View File

@ -113,6 +113,7 @@ func Convert_authentication_TokenReview_To_v1beta1_TokenReview(in *authenticatio
func autoConvert_v1beta1_TokenReviewSpec_To_authentication_TokenReviewSpec(in *v1beta1.TokenReviewSpec, out *authentication.TokenReviewSpec, s conversion.Scope) error { func autoConvert_v1beta1_TokenReviewSpec_To_authentication_TokenReviewSpec(in *v1beta1.TokenReviewSpec, out *authentication.TokenReviewSpec, s conversion.Scope) error {
out.Token = in.Token out.Token = in.Token
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
return nil return nil
} }
@ -123,6 +124,7 @@ func Convert_v1beta1_TokenReviewSpec_To_authentication_TokenReviewSpec(in *v1bet
func autoConvert_authentication_TokenReviewSpec_To_v1beta1_TokenReviewSpec(in *authentication.TokenReviewSpec, out *v1beta1.TokenReviewSpec, s conversion.Scope) error { func autoConvert_authentication_TokenReviewSpec_To_v1beta1_TokenReviewSpec(in *authentication.TokenReviewSpec, out *v1beta1.TokenReviewSpec, s conversion.Scope) error {
out.Token = in.Token out.Token = in.Token
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
return nil return nil
} }
@ -136,6 +138,7 @@ func autoConvert_v1beta1_TokenReviewStatus_To_authentication_TokenReviewStatus(i
if err := Convert_v1beta1_UserInfo_To_authentication_UserInfo(&in.User, &out.User, s); err != nil { if err := Convert_v1beta1_UserInfo_To_authentication_UserInfo(&in.User, &out.User, s); err != nil {
return err return err
} }
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
out.Error = in.Error out.Error = in.Error
return nil return nil
} }
@ -150,6 +153,7 @@ func autoConvert_authentication_TokenReviewStatus_To_v1beta1_TokenReviewStatus(i
if err := Convert_authentication_UserInfo_To_v1beta1_UserInfo(&in.User, &out.User, s); err != nil { if err := Convert_authentication_UserInfo_To_v1beta1_UserInfo(&in.User, &out.User, s); err != nil {
return err return err
} }
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
out.Error = in.Error out.Error = in.Error
return nil return nil
} }

View File

@ -136,7 +136,7 @@ func (in *TokenReview) DeepCopyInto(out *TokenReview) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status) in.Status.DeepCopyInto(&out.Status)
return return
} }
@ -162,6 +162,11 @@ func (in *TokenReview) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TokenReviewSpec) DeepCopyInto(out *TokenReviewSpec) { func (in *TokenReviewSpec) DeepCopyInto(out *TokenReviewSpec) {
*out = *in *out = *in
if in.Audiences != nil {
in, out := &in.Audiences, &out.Audiences
*out = make([]string, len(*in))
copy(*out, *in)
}
return return
} }
@ -179,6 +184,11 @@ func (in *TokenReviewSpec) DeepCopy() *TokenReviewSpec {
func (in *TokenReviewStatus) DeepCopyInto(out *TokenReviewStatus) { func (in *TokenReviewStatus) DeepCopyInto(out *TokenReviewStatus) {
*out = *in *out = *in
in.User.DeepCopyInto(&out.User) in.User.DeepCopyInto(&out.User)
if in.Audiences != nil {
in, out := &in.Audiences, &out.Audiences
*out = make([]string, len(*in))
copy(*out, *in)
}
return return
} }

View File

@ -179,7 +179,7 @@ func (config Config) New() (authenticator.Request, *spec.SecurityDefinitions, er
tokenAuthenticators = append(tokenAuthenticators, oidcAuth) tokenAuthenticators = append(tokenAuthenticators, oidcAuth)
} }
if len(config.WebhookTokenAuthnConfigFile) > 0 { if len(config.WebhookTokenAuthnConfigFile) > 0 {
webhookTokenAuth, err := newWebhookTokenAuthenticator(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnCacheTTL) webhookTokenAuth, err := newWebhookTokenAuthenticator(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnCacheTTL, config.APIAudiences)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -318,8 +318,8 @@ func newAuthenticatorFromClientCAFile(clientCAFile string) (authenticator.Reques
return x509.New(opts, x509.CommonNameUserConversion), nil return x509.New(opts, x509.CommonNameUserConversion), nil
} }
func newWebhookTokenAuthenticator(webhookConfigFile string, ttl time.Duration) (authenticator.Token, error) { func newWebhookTokenAuthenticator(webhookConfigFile string, ttl time.Duration, implicitAuds authenticator.Audiences) (authenticator.Token, error) {
webhookTokenAuthenticator, err := webhook.New(webhookConfigFile) webhookTokenAuthenticator, err := webhook.New(webhookConfigFile, implicitAuds)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -335,7 +335,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
// handlers that we have. // handlers that we have.
restStorageProviders := []RESTStorageProvider{ restStorageProviders := []RESTStorageProvider{
auditregistrationrest.RESTStorageProvider{}, auditregistrationrest.RESTStorageProvider{},
authenticationrest.RESTStorageProvider{Authenticator: c.GenericConfig.Authentication.Authenticator}, authenticationrest.RESTStorageProvider{Authenticator: c.GenericConfig.Authentication.Authenticator, APIAudiences: c.GenericConfig.Authentication.APIAudiences},
authorizationrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer, RuleResolver: c.GenericConfig.RuleResolver}, authorizationrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer, RuleResolver: c.GenericConfig.RuleResolver},
autoscalingrest.RESTStorageProvider{}, autoscalingrest.RESTStorageProvider{},
batchrest.RESTStorageProvider{}, batchrest.RESTStorageProvider{},

View File

@ -31,6 +31,7 @@ import (
type RESTStorageProvider struct { type RESTStorageProvider struct {
Authenticator authenticator.Request Authenticator authenticator.Request
APIAudiences authenticator.Audiences
} }
func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool) { func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool) {
@ -56,7 +57,7 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorag
func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage { func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage {
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
// tokenreviews // tokenreviews
tokenReviewStorage := tokenreview.NewREST(p.Authenticator) tokenReviewStorage := tokenreview.NewREST(p.Authenticator, p.APIAudiences)
storage["tokenreviews"] = tokenReviewStorage storage["tokenreviews"] = tokenReviewStorage
return storage return storage
@ -65,7 +66,7 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag
func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage { func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage {
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
// tokenreviews // tokenreviews
tokenReviewStorage := tokenreview.NewREST(p.Authenticator) tokenReviewStorage := tokenreview.NewREST(p.Authenticator, p.APIAudiences)
storage["tokenreviews"] = tokenReviewStorage storage["tokenreviews"] = tokenReviewStorage
return storage return storage

View File

@ -17,6 +17,7 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library", "//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
], ],
) )

View File

@ -18,6 +18,7 @@ package tokenreview
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"net/http" "net/http"
@ -27,15 +28,22 @@ import (
"k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/authenticator"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/apis/authentication" "k8s.io/kubernetes/pkg/apis/authentication"
) )
var badAuthenticatorAuds = apierrors.NewInternalError(errors.New("error validating audiences"))
type REST struct { type REST struct {
tokenAuthenticator authenticator.Request tokenAuthenticator authenticator.Request
apiAudiences []string
} }
func NewREST(tokenAuthenticator authenticator.Request) *REST { func NewREST(tokenAuthenticator authenticator.Request, apiAudiences []string) *REST {
return &REST{tokenAuthenticator: tokenAuthenticator} return &REST{
tokenAuthenticator: tokenAuthenticator,
apiAudiences: apiAudiences,
}
} }
func (r *REST) NamespaceScoped() bool { func (r *REST) NamespaceScoped() bool {
@ -68,14 +76,24 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation
fakeReq := &http.Request{Header: http.Header{}} fakeReq := &http.Request{Header: http.Header{}}
fakeReq.Header.Add("Authorization", "Bearer "+tokenReview.Spec.Token) fakeReq.Header.Add("Authorization", "Bearer "+tokenReview.Spec.Token)
auds := tokenReview.Spec.Audiences
if len(auds) == 0 {
auds = r.apiAudiences
}
if len(auds) > 0 {
fakeReq = fakeReq.WithContext(authenticator.WithAudiences(fakeReq.Context(), auds))
}
resp, ok, err := r.tokenAuthenticator.AuthenticateRequest(fakeReq) resp, ok, err := r.tokenAuthenticator.AuthenticateRequest(fakeReq)
tokenReview.Status.Authenticated = ok tokenReview.Status.Authenticated = ok
if err != nil { if err != nil {
tokenReview.Status.Error = err.Error() tokenReview.Status.Error = err.Error()
} }
// TODO(mikedanese): verify the response audience matches one of apiAuds if if len(auds) > 0 && resp != nil && len(authenticator.Audiences(auds).Intersect(resp.Audiences)) == 0 {
// non-empty klog.Errorf("error validating audience. want=%q got=%q", auds, resp.Audiences)
return nil, badAuthenticatorAuds
}
if resp != nil && resp.User != nil { if resp != nil && resp.User != nil {
tokenReview.Status.User = authentication.UserInfo{ tokenReview.Status.User = authentication.UserInfo{
@ -87,6 +105,7 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation
for k, v := range resp.User.GetExtra() { for k, v := range resp.User.GetExtra() {
tokenReview.Status.User.Extra[k] = authentication.ExtraValue(v) tokenReview.Status.User.Extra[k] = authentication.ExtraValue(v)
} }
tokenReview.Status.Audiences = resp.Audiences
} }
return tokenReview, nil return tokenReview, nil

View File

@ -355,6 +355,21 @@ func (m *TokenReviewSpec) MarshalTo(dAtA []byte) (int, error) {
i++ i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Token))) i = encodeVarintGenerated(dAtA, i, uint64(len(m.Token)))
i += copy(dAtA[i:], m.Token) i += copy(dAtA[i:], m.Token)
if len(m.Audiences) > 0 {
for _, s := range m.Audiences {
dAtA[i] = 0x12
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil return i, nil
} }
@ -393,6 +408,21 @@ func (m *TokenReviewStatus) MarshalTo(dAtA []byte) (int, error) {
i++ i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Error))) i = encodeVarintGenerated(dAtA, i, uint64(len(m.Error)))
i += copy(dAtA[i:], m.Error) i += copy(dAtA[i:], m.Error)
if len(m.Audiences) > 0 {
for _, s := range m.Audiences {
dAtA[i] = 0x22
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil return i, nil
} }
@ -561,6 +591,12 @@ func (m *TokenReviewSpec) Size() (n int) {
_ = l _ = l
l = len(m.Token) l = len(m.Token)
n += 1 + l + sovGenerated(uint64(l)) n += 1 + l + sovGenerated(uint64(l))
if len(m.Audiences) > 0 {
for _, s := range m.Audiences {
l = len(s)
n += 1 + l + sovGenerated(uint64(l))
}
}
return n return n
} }
@ -572,6 +608,12 @@ func (m *TokenReviewStatus) Size() (n int) {
n += 1 + l + sovGenerated(uint64(l)) n += 1 + l + sovGenerated(uint64(l))
l = len(m.Error) l = len(m.Error)
n += 1 + l + sovGenerated(uint64(l)) n += 1 + l + sovGenerated(uint64(l))
if len(m.Audiences) > 0 {
for _, s := range m.Audiences {
l = len(s)
n += 1 + l + sovGenerated(uint64(l))
}
}
return n return n
} }
@ -679,6 +721,7 @@ func (this *TokenReviewSpec) String() string {
} }
s := strings.Join([]string{`&TokenReviewSpec{`, s := strings.Join([]string{`&TokenReviewSpec{`,
`Token:` + fmt.Sprintf("%v", this.Token) + `,`, `Token:` + fmt.Sprintf("%v", this.Token) + `,`,
`Audiences:` + fmt.Sprintf("%v", this.Audiences) + `,`,
`}`, `}`,
}, "") }, "")
return s return s
@ -691,6 +734,7 @@ func (this *TokenReviewStatus) String() string {
`Authenticated:` + fmt.Sprintf("%v", this.Authenticated) + `,`, `Authenticated:` + fmt.Sprintf("%v", this.Authenticated) + `,`,
`User:` + strings.Replace(strings.Replace(this.User.String(), "UserInfo", "UserInfo", 1), `&`, ``, 1) + `,`, `User:` + strings.Replace(strings.Replace(this.User.String(), "UserInfo", "UserInfo", 1), `&`, ``, 1) + `,`,
`Error:` + fmt.Sprintf("%v", this.Error) + `,`, `Error:` + fmt.Sprintf("%v", this.Error) + `,`,
`Audiences:` + fmt.Sprintf("%v", this.Audiences) + `,`,
`}`, `}`,
}, "") }, "")
return s return s
@ -1550,6 +1594,35 @@ func (m *TokenReviewSpec) Unmarshal(dAtA []byte) error {
} }
m.Token = string(dAtA[iNdEx:postIndex]) m.Token = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Audiences", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Audiences = append(m.Audiences, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:]) skippy, err := skipGenerated(dAtA[iNdEx:])
@ -1679,6 +1752,35 @@ func (m *TokenReviewStatus) Unmarshal(dAtA []byte) error {
} }
m.Error = string(dAtA[iNdEx:postIndex]) m.Error = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Audiences", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Audiences = append(m.Audiences, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:]) skippy, err := skipGenerated(dAtA[iNdEx:])
@ -2070,61 +2172,62 @@ func init() {
} }
var fileDescriptorGenerated = []byte{ var fileDescriptorGenerated = []byte{
// 892 bytes of a gzipped FileDescriptorProto // 900 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xcf, 0x8f, 0xdb, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xcf, 0x6f, 0xe3, 0x44,
0x14, 0x8e, 0xf3, 0x63, 0xb5, 0x99, 0x74, 0x97, 0xdd, 0x29, 0x95, 0xa2, 0x05, 0xec, 0x60, 0x24, 0x14, 0x8e, 0xf3, 0xa3, 0x4a, 0x26, 0xdb, 0xd2, 0xce, 0xb2, 0x52, 0x54, 0xc0, 0x2e, 0x41, 0x42,
0x14, 0x01, 0xb5, 0x9b, 0x08, 0x95, 0xaa, 0x48, 0x48, 0x6b, 0x36, 0x82, 0x08, 0x41, 0xab, 0x69, 0x15, 0xb0, 0xf6, 0x26, 0x42, 0xb0, 0x5a, 0x24, 0xa4, 0x9a, 0x46, 0x10, 0x21, 0xd8, 0xd5, 0xec,
0x77, 0x41, 0x9c, 0x98, 0xd8, 0x6f, 0xb3, 0x26, 0x78, 0x6c, 0xec, 0x71, 0x68, 0x6e, 0xfd, 0x13, 0xb6, 0x20, 0x4e, 0x4c, 0xec, 0xd7, 0xc4, 0x04, 0x8f, 0x8d, 0x3d, 0x0e, 0x9b, 0xdb, 0xfe, 0x09,
0x38, 0x82, 0xc4, 0x81, 0x3f, 0x02, 0x89, 0x23, 0xd7, 0x3d, 0x56, 0x9c, 0x7a, 0x40, 0x11, 0x6b, 0x1c, 0x41, 0xe2, 0xc0, 0x1f, 0x81, 0xc4, 0xbf, 0xd0, 0xe3, 0x8a, 0xd3, 0x1e, 0x50, 0x44, 0xcd,
0xfe, 0x05, 0x4e, 0x9c, 0xd0, 0x8c, 0x67, 0xe3, 0xfc, 0xd8, 0x4d, 0x73, 0xea, 0x2d, 0xf3, 0xde, 0x95, 0x23, 0x27, 0x4e, 0x68, 0xc6, 0xd3, 0x38, 0x4e, 0xda, 0x34, 0x27, 0x6e, 0x9e, 0xf7, 0xbe,
0xf7, 0xbe, 0x79, 0xef, 0x9b, 0x2f, 0xcf, 0xa8, 0x37, 0xba, 0x97, 0x58, 0x7e, 0x68, 0x8f, 0xd2, 0xf7, 0xbd, 0x37, 0xdf, 0x7c, 0x9e, 0x41, 0xbd, 0xf1, 0xfd, 0xd8, 0xf4, 0x02, 0x6b, 0x9c, 0x0c,
0x01, 0xc4, 0x0c, 0x38, 0x24, 0xf6, 0x18, 0x98, 0x17, 0xc6, 0xb6, 0x4a, 0xd0, 0xc8, 0xb7, 0x69, 0x20, 0x62, 0xc0, 0x21, 0xb6, 0x26, 0xc0, 0xdc, 0x20, 0xb2, 0x54, 0x82, 0x86, 0x9e, 0x45, 0x13,
0xca, 0xcf, 0x80, 0x71, 0xdf, 0xa5, 0xdc, 0x0f, 0x99, 0x3d, 0xee, 0xd8, 0x43, 0x60, 0x10, 0x53, 0x3e, 0x02, 0xc6, 0x3d, 0x87, 0x72, 0x2f, 0x60, 0xd6, 0xa4, 0x63, 0x0d, 0x81, 0x41, 0x44, 0x39,
0x0e, 0x9e, 0x15, 0xc5, 0x21, 0x0f, 0xf1, 0xeb, 0x39, 0xda, 0xa2, 0x91, 0x6f, 0x2d, 0xa2, 0xad, 0xb8, 0x66, 0x18, 0x05, 0x3c, 0xc0, 0xaf, 0x66, 0x68, 0x93, 0x86, 0x9e, 0x59, 0x44, 0x9b, 0x93,
0x71, 0xe7, 0xe0, 0xf6, 0xd0, 0xe7, 0x67, 0xe9, 0xc0, 0x72, 0xc3, 0xc0, 0x1e, 0x86, 0xc3, 0xd0, 0xce, 0xfe, 0xdd, 0xa1, 0xc7, 0x47, 0xc9, 0xc0, 0x74, 0x02, 0xdf, 0x1a, 0x06, 0xc3, 0xc0, 0x92,
0x96, 0x45, 0x83, 0xf4, 0x54, 0x9e, 0xe4, 0x41, 0xfe, 0xca, 0xc9, 0x0e, 0xde, 0x2f, 0xae, 0x0e, 0x45, 0x83, 0xe4, 0x4c, 0xae, 0xe4, 0x42, 0x7e, 0x65, 0x64, 0xfb, 0xef, 0xe6, 0xad, 0x7d, 0xea,
0xa8, 0x7b, 0xe6, 0x33, 0x88, 0x27, 0x76, 0x34, 0x1a, 0x8a, 0x40, 0x62, 0x07, 0xc0, 0xe9, 0x15, 0x8c, 0x3c, 0x06, 0xd1, 0xd4, 0x0a, 0xc7, 0x43, 0x11, 0x88, 0x2d, 0x1f, 0x38, 0xbd, 0x62, 0x84,
0x2d, 0x1c, 0xd8, 0xd7, 0x55, 0xc5, 0x29, 0xe3, 0x7e, 0x00, 0x2b, 0x05, 0x77, 0x5f, 0x54, 0x90, 0x7d, 0xeb, 0xba, 0xaa, 0x28, 0x61, 0xdc, 0xf3, 0x61, 0xa5, 0xe0, 0xbd, 0x9b, 0x0a, 0x62, 0x67,
0xb8, 0x67, 0x10, 0xd0, 0xe5, 0x3a, 0xf3, 0x4f, 0x0d, 0xbd, 0xea, 0x84, 0x29, 0xf3, 0x1e, 0x0c, 0x04, 0x3e, 0x5d, 0xae, 0x6b, 0xff, 0xae, 0xa1, 0x97, 0xed, 0x20, 0x61, 0xee, 0xc3, 0xc1, 0x37,
0xbe, 0x05, 0x97, 0x13, 0x38, 0x85, 0x18, 0x98, 0x0b, 0xb8, 0x85, 0xaa, 0x23, 0x9f, 0x79, 0x4d, 0xe0, 0x70, 0x02, 0x67, 0x10, 0x01, 0x73, 0x00, 0x1f, 0xa0, 0xea, 0xd8, 0x63, 0x6e, 0x4b, 0x3b,
0xad, 0xa5, 0xb5, 0xeb, 0xce, 0x8d, 0xf3, 0xa9, 0x51, 0xca, 0xa6, 0x46, 0xf5, 0x33, 0x9f, 0x79, 0xd0, 0x0e, 0x1b, 0xf6, 0xad, 0xf3, 0x99, 0x51, 0x4a, 0x67, 0x46, 0xf5, 0x53, 0x8f, 0xb9, 0x44,
0x44, 0x66, 0x70, 0x17, 0x21, 0xfa, 0xb0, 0x7f, 0x02, 0x71, 0xe2, 0x87, 0xac, 0x59, 0x96, 0x38, 0x66, 0x70, 0x17, 0x21, 0xfa, 0xa8, 0x7f, 0x0a, 0x51, 0xec, 0x05, 0xac, 0x55, 0x96, 0x38, 0xac,
0xac, 0x70, 0xe8, 0x70, 0x96, 0x21, 0x73, 0x28, 0xc1, 0xca, 0x68, 0x00, 0xcd, 0xca, 0x22, 0xeb, 0x70, 0xe8, 0x68, 0x9e, 0x21, 0x0b, 0x28, 0xc1, 0xca, 0xa8, 0x0f, 0xad, 0x4a, 0x91, 0xf5, 0x73,
0x17, 0x34, 0x00, 0x22, 0x33, 0xd8, 0x41, 0x95, 0xb4, 0x7f, 0xd4, 0xac, 0x4a, 0xc0, 0x1d, 0x05, 0xea, 0x03, 0x91, 0x19, 0x6c, 0xa3, 0x4a, 0xd2, 0x3f, 0x6e, 0x55, 0x25, 0xe0, 0x9e, 0x02, 0x54,
0xa8, 0x1c, 0xf7, 0x8f, 0xfe, 0x9b, 0x1a, 0x6f, 0x5e, 0x37, 0x24, 0x9f, 0x44, 0x90, 0x58, 0xc7, 0x4e, 0xfa, 0xc7, 0xff, 0xce, 0x8c, 0xd7, 0xaf, 0xdb, 0x24, 0x9f, 0x86, 0x10, 0x9b, 0x27, 0xfd,
0xfd, 0x23, 0x22, 0x8a, 0xcd, 0x0f, 0x10, 0xea, 0x3d, 0xe1, 0x31, 0x3d, 0xa1, 0xdf, 0xa5, 0x80, 0x63, 0x22, 0x8a, 0xdb, 0xef, 0x23, 0xd4, 0x7b, 0xca, 0x23, 0x7a, 0x4a, 0xbf, 0x4d, 0x00, 0x1b,
0x0d, 0x54, 0xf3, 0x39, 0x04, 0x49, 0x53, 0x6b, 0x55, 0xda, 0x75, 0xa7, 0x9e, 0x4d, 0x8d, 0x5a, 0xa8, 0xe6, 0x71, 0xf0, 0xe3, 0x96, 0x76, 0x50, 0x39, 0x6c, 0xd8, 0x8d, 0x74, 0x66, 0xd4, 0xfa,
0x5f, 0x04, 0x48, 0x1e, 0xbf, 0xbf, 0xfd, 0xd3, 0xaf, 0x46, 0xe9, 0xe9, 0x5f, 0xad, 0x92, 0xf9, 0x22, 0x40, 0xb2, 0xf8, 0x83, 0xfa, 0x8f, 0xbf, 0x18, 0xa5, 0x67, 0x7f, 0x1c, 0x94, 0xda, 0x3f,
0x4b, 0x19, 0xdd, 0x78, 0x1c, 0x8e, 0x80, 0x11, 0xf8, 0x3e, 0x85, 0x84, 0xe3, 0x6f, 0xd0, 0xb6, 0x97, 0xd1, 0xad, 0x27, 0xc1, 0x18, 0x18, 0x81, 0xef, 0x12, 0x88, 0x39, 0xfe, 0x1a, 0xd5, 0xc5,
0x78, 0x22, 0x8f, 0x72, 0x2a, 0x95, 0x68, 0x74, 0xef, 0x58, 0x85, 0x3b, 0x66, 0x4d, 0x58, 0xd1, 0x11, 0xb9, 0x94, 0x53, 0xa9, 0x44, 0xb3, 0x7b, 0xcf, 0xcc, 0xdd, 0x31, 0x1f, 0xc2, 0x0c, 0xc7,
0x68, 0x28, 0x02, 0x89, 0x25, 0xd0, 0xd6, 0xb8, 0x63, 0xe5, 0x72, 0x7e, 0x0e, 0x9c, 0x16, 0x9a, 0x43, 0x11, 0x88, 0x4d, 0x81, 0x36, 0x27, 0x1d, 0x33, 0x93, 0xf3, 0x33, 0xe0, 0x34, 0xd7, 0x24,
0x14, 0x31, 0x32, 0x63, 0xc5, 0x0f, 0x51, 0x35, 0x89, 0xc0, 0x95, 0xfa, 0x35, 0xba, 0x96, 0xb5, 0x8f, 0x91, 0x39, 0x2b, 0x7e, 0x84, 0xaa, 0x71, 0x08, 0x8e, 0xd4, 0xaf, 0xd9, 0x35, 0xcd, 0x75,
0xce, 0x7b, 0xd6, 0x7c, 0x6f, 0x8f, 0x22, 0x70, 0x0b, 0x05, 0xc5, 0x89, 0x48, 0x26, 0xfc, 0x15, 0xde, 0x33, 0x17, 0x67, 0x7b, 0x1c, 0x82, 0x93, 0x2b, 0x28, 0x56, 0x44, 0x32, 0xe1, 0x2f, 0xd1,
0xda, 0x4a, 0x38, 0xe5, 0x69, 0x22, 0x55, 0x5e, 0xec, 0xf8, 0x45, 0x9c, 0xb2, 0xce, 0xd9, 0x55, 0x56, 0xcc, 0x29, 0x4f, 0x62, 0xa9, 0x72, 0x71, 0xe2, 0x9b, 0x38, 0x65, 0x9d, 0xbd, 0xa3, 0x58,
0xac, 0x5b, 0xf9, 0x99, 0x28, 0x3e, 0xf3, 0x5f, 0x0d, 0xed, 0x2d, 0xb7, 0x80, 0xdf, 0x45, 0x75, 0xb7, 0xb2, 0x35, 0x51, 0x7c, 0xed, 0x7f, 0x34, 0xb4, 0xbb, 0x3c, 0x02, 0x7e, 0x1b, 0x35, 0x68,
0x9a, 0x7a, 0xbe, 0x30, 0xcd, 0xa5, 0xc4, 0x3b, 0xd9, 0xd4, 0xa8, 0x1f, 0x5e, 0x06, 0x49, 0x91, 0xe2, 0x7a, 0xc2, 0x34, 0x97, 0x12, 0x6f, 0xa7, 0x33, 0xa3, 0x71, 0x74, 0x19, 0x24, 0x79, 0x1e,
0xc7, 0x0c, 0xed, 0x0e, 0x16, 0xdc, 0xa6, 0x7a, 0xec, 0xae, 0xef, 0xf1, 0x2a, 0x87, 0x3a, 0x38, 0x33, 0xb4, 0x33, 0x28, 0xb8, 0x4d, 0xcd, 0xd8, 0x5d, 0x3f, 0xe3, 0x55, 0x0e, 0xb5, 0x71, 0x3a,
0x9b, 0x1a, 0xbb, 0x8b, 0x19, 0xb2, 0xc4, 0x8e, 0x3f, 0x46, 0xfb, 0xf0, 0x24, 0xf2, 0x63, 0xc9, 0x33, 0x76, 0x8a, 0x19, 0xb2, 0xc4, 0x8e, 0x3f, 0x42, 0x7b, 0xf0, 0x34, 0xf4, 0x22, 0xc9, 0xf4,
0xf4, 0x08, 0xdc, 0x90, 0x79, 0x89, 0xf4, 0x56, 0xc5, 0xb9, 0x95, 0x4d, 0x8d, 0xfd, 0xde, 0x72, 0x18, 0x9c, 0x80, 0xb9, 0xb1, 0xf4, 0x56, 0xc5, 0xbe, 0x93, 0xce, 0x8c, 0xbd, 0xde, 0x72, 0x92,
0x92, 0xac, 0xe2, 0xcd, 0xdf, 0x34, 0x84, 0x57, 0x55, 0xc2, 0x6f, 0xa1, 0x1a, 0x17, 0x51, 0xf5, 0xac, 0xe2, 0xdb, 0xbf, 0x6a, 0x08, 0xaf, 0xaa, 0x84, 0xdf, 0x40, 0x35, 0x2e, 0xa2, 0xea, 0x17,
0x17, 0xd9, 0x51, 0xa2, 0xd5, 0x72, 0x68, 0x9e, 0xc3, 0x13, 0x74, 0xb3, 0x20, 0x7c, 0xec, 0x07, 0xd9, 0x56, 0xa2, 0xd5, 0x32, 0x68, 0x96, 0xc3, 0x53, 0x74, 0x3b, 0x27, 0x7c, 0xe2, 0xf9, 0x10,
0x90, 0x70, 0x1a, 0x44, 0xea, 0xb5, 0xdf, 0xd9, 0xcc, 0x4b, 0xa2, 0xcc, 0x79, 0x4d, 0xd1, 0xdf, 0x73, 0xea, 0x87, 0xea, 0xb4, 0xdf, 0xda, 0xcc, 0x4b, 0xa2, 0xcc, 0x7e, 0x45, 0xd1, 0xdf, 0xee,
0xec, 0xad, 0xd2, 0x91, 0xab, 0xee, 0x30, 0x7f, 0x2e, 0xa3, 0x86, 0x6a, 0x7b, 0xec, 0xc3, 0x0f, 0xad, 0xd2, 0x91, 0xab, 0x7a, 0xb4, 0x7f, 0x2a, 0xa3, 0xa6, 0x1a, 0x7b, 0xe2, 0xc1, 0xf7, 0xff,
0x2f, 0xc1, 0xcb, 0x0f, 0x16, 0xbc, 0x7c, 0x7b, 0x23, 0xdf, 0x89, 0xd6, 0xae, 0xb5, 0xf2, 0x97, 0x83, 0x97, 0x1f, 0x16, 0xbc, 0x7c, 0x77, 0x23, 0xdf, 0x89, 0xd1, 0xae, 0xb5, 0xf2, 0x17, 0x4b,
0x4b, 0x56, 0xb6, 0x37, 0xa7, 0x5c, 0xef, 0xe4, 0xbb, 0xe8, 0x95, 0xa5, 0xfb, 0x37, 0x7a, 0x4e, 0x56, 0xb6, 0x36, 0xa7, 0x5c, 0xef, 0x64, 0x07, 0xbd, 0xb4, 0xd4, 0x7f, 0xb3, 0xe3, 0x2c, 0x98,
0xf3, 0x0f, 0x0d, 0xed, 0xaf, 0xdc, 0x82, 0x3f, 0x44, 0x3b, 0x73, 0xcd, 0x40, 0xbe, 0x34, 0xb7, 0xbd, 0xbc, 0xde, 0xec, 0xed, 0xbf, 0x35, 0xb4, 0xb7, 0x32, 0x12, 0xfe, 0x00, 0x6d, 0x2f, 0x4c,
0x9d, 0x5b, 0x8a, 0x62, 0xe7, 0x70, 0x3e, 0x49, 0x16, 0xb1, 0xf8, 0x53, 0x54, 0x4d, 0x13, 0x88, 0x0e, 0xd9, 0x0d, 0x5b, 0xb7, 0xef, 0xa8, 0x7e, 0xdb, 0x47, 0x8b, 0x49, 0x52, 0xc4, 0xe2, 0x4f,
0x95, 0x68, 0x6f, 0xaf, 0x9f, 0xf0, 0x38, 0x81, 0xb8, 0xcf, 0x4e, 0xc3, 0x42, 0x2d, 0x11, 0x21, 0x50, 0x35, 0x89, 0x21, 0x52, 0x0a, 0xbf, 0xb9, 0x5e, 0x8e, 0x93, 0x18, 0xa2, 0x3e, 0x3b, 0x0b,
0x92, 0x41, 0x4c, 0x00, 0x71, 0x1c, 0xc6, 0x6a, 0xbb, 0xce, 0x26, 0xe8, 0x89, 0x20, 0xc9, 0x73, 0x72, 0x69, 0x45, 0x84, 0x48, 0x06, 0xb1, 0x5d, 0x88, 0xa2, 0x20, 0x52, 0x57, 0xf1, 0x7c, 0xbb,
0xe6, 0xef, 0x65, 0xb4, 0x7d, 0xc9, 0x82, 0xdf, 0x43, 0xdb, 0xa2, 0x52, 0xae, 0xe4, 0x7c, 0xec, 0x3d, 0x11, 0x24, 0x59, 0xae, 0xb8, 0xdd, 0xea, 0x0d, 0xdb, 0xfd, 0xad, 0x8c, 0xea, 0x97, 0x2d,
0x3d, 0x55, 0x24, 0x31, 0x22, 0x4e, 0x66, 0x08, 0xfc, 0x06, 0xaa, 0xa4, 0xbe, 0xa7, 0x36, 0x7d, 0xf1, 0x3b, 0xa8, 0x2e, 0xda, 0xc8, 0xcb, 0x3e, 0x13, 0x74, 0x57, 0x75, 0x90, 0x18, 0x11, 0x27,
0x63, 0x6e, 0x35, 0x13, 0x11, 0xc7, 0x26, 0xda, 0x1a, 0xc6, 0x61, 0x1a, 0x89, 0xc7, 0x12, 0x5b, 0x73, 0x04, 0x7e, 0x0d, 0x55, 0x12, 0xcf, 0x55, 0x6f, 0x48, 0x73, 0xe1, 0xd2, 0x27, 0x22, 0x8e,
0x00, 0x09, 0xdd, 0x3f, 0x91, 0x11, 0xa2, 0x32, 0xf8, 0x04, 0xd5, 0x40, 0x6c, 0xe6, 0x66, 0xb5, 0xdb, 0x68, 0x6b, 0x18, 0x05, 0x49, 0x28, 0x6c, 0x20, 0x66, 0x40, 0xe2, 0x44, 0x3f, 0x96, 0x11,
0x55, 0x69, 0x37, 0xba, 0x9d, 0xcd, 0xa6, 0xb5, 0xe4, 0x36, 0xef, 0x31, 0x1e, 0x4f, 0xe6, 0xa6, 0xa2, 0x32, 0xf8, 0x14, 0xd5, 0x40, 0xdc, 0xf9, 0x72, 0xcc, 0x66, 0xb7, 0xb3, 0x99, 0x34, 0xa6,
0x12, 0x31, 0x92, 0xd3, 0x1d, 0x0c, 0xd4, 0xc6, 0x97, 0x18, 0xbc, 0x87, 0x2a, 0x23, 0x98, 0xe4, 0x7c, 0x27, 0x7a, 0x8c, 0x47, 0xd3, 0x05, 0x09, 0x44, 0x8c, 0x64, 0x74, 0xfb, 0x03, 0xf5, 0x96,
0x13, 0x11, 0xf1, 0x13, 0x7f, 0x84, 0x6a, 0x63, 0xf1, 0x31, 0x50, 0x2a, 0xb7, 0xd7, 0xdf, 0x5b, 0x48, 0x0c, 0xde, 0x45, 0x95, 0x31, 0x4c, 0xb3, 0x1d, 0x11, 0xf1, 0x89, 0x3f, 0x44, 0xb5, 0x89,
0x7c, 0x3c, 0x48, 0x5e, 0x76, 0xbf, 0x7c, 0x4f, 0x73, 0xda, 0xe7, 0x17, 0x7a, 0xe9, 0xd9, 0x85, 0x78, 0x66, 0xd4, 0x91, 0x1c, 0xae, 0xef, 0x9b, 0x3f, 0x4b, 0x24, 0x2b, 0x7b, 0x50, 0xbe, 0xaf,
0x5e, 0x7a, 0x7e, 0xa1, 0x97, 0x9e, 0x66, 0xba, 0x76, 0x9e, 0xe9, 0xda, 0xb3, 0x4c, 0xd7, 0x9e, 0xd9, 0x87, 0xe7, 0x17, 0x7a, 0xe9, 0xf9, 0x85, 0x5e, 0x7a, 0x71, 0xa1, 0x97, 0x9e, 0xa5, 0xba,
0x67, 0xba, 0xf6, 0x77, 0xa6, 0x6b, 0x3f, 0xfe, 0xa3, 0x97, 0xbe, 0x2e, 0x8f, 0x3b, 0xff, 0x07, 0x76, 0x9e, 0xea, 0xda, 0xf3, 0x54, 0xd7, 0x5e, 0xa4, 0xba, 0xf6, 0x67, 0xaa, 0x6b, 0x3f, 0xfc,
0x00, 0x00, 0xff, 0xff, 0x5e, 0x8d, 0x94, 0x78, 0x88, 0x08, 0x00, 0x00, 0xa5, 0x97, 0xbe, 0x2a, 0x4f, 0x3a, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x04, 0x81, 0x6f,
0xe2, 0x08, 0x00, 0x00,
} }

View File

@ -118,6 +118,14 @@ message TokenReviewSpec {
// Token is the opaque bearer token. // Token is the opaque bearer token.
// +optional // +optional
optional string token = 1; optional string token = 1;
// Audiences is a list of the identifiers that the resource server presented
// with the token identifies as. Audience-aware token authenticators will
// verify that the token was intended for at least one of the audiences in
// this list. If no audiences are provided, the audience will default to the
// audience of the Kubernetes apiserver.
// +optional
repeated string audiences = 2;
} }
// TokenReviewStatus is the result of the token authentication request. // TokenReviewStatus is the result of the token authentication request.
@ -130,6 +138,18 @@ message TokenReviewStatus {
// +optional // +optional
optional UserInfo user = 2; optional UserInfo user = 2;
// Audiences are audience identifiers chosen by the authenticator that are
// compatible with both the TokenReview and token. An identifier is any
// identifier in the intersection of the TokenReviewSpec audiences and the
// token's audiences. A client of the TokenReview API that sets the
// spec.audiences field should validate that a compatible audience identifier
// is returned in the status.audiences field to ensure that the TokenReview
// server is audience aware. If a TokenReview returns an empty
// status.audience field where status.authenticated is "true", the token is
// valid against the audience of the Kubernetes API server.
// +optional
repeated string audiences = 4;
// Error indicates that the token couldn't be checked // Error indicates that the token couldn't be checked
// +optional // +optional
optional string error = 3; optional string error = 3;

View File

@ -64,6 +64,13 @@ type TokenReviewSpec struct {
// Token is the opaque bearer token. // Token is the opaque bearer token.
// +optional // +optional
Token string `json:"token,omitempty" protobuf:"bytes,1,opt,name=token"` Token string `json:"token,omitempty" protobuf:"bytes,1,opt,name=token"`
// Audiences is a list of the identifiers that the resource server presented
// with the token identifies as. Audience-aware token authenticators will
// verify that the token was intended for at least one of the audiences in
// this list. If no audiences are provided, the audience will default to the
// audience of the Kubernetes apiserver.
// +optional
Audiences []string `json:"audiences,omitempty" protobuf:"bytes,2,rep,name=audiences"`
} }
// TokenReviewStatus is the result of the token authentication request. // TokenReviewStatus is the result of the token authentication request.
@ -74,6 +81,17 @@ type TokenReviewStatus struct {
// User is the UserInfo associated with the provided token. // User is the UserInfo associated with the provided token.
// +optional // +optional
User UserInfo `json:"user,omitempty" protobuf:"bytes,2,opt,name=user"` User UserInfo `json:"user,omitempty" protobuf:"bytes,2,opt,name=user"`
// Audiences are audience identifiers chosen by the authenticator that are
// compatible with both the TokenReview and token. An identifier is any
// identifier in the intersection of the TokenReviewSpec audiences and the
// token's audiences. A client of the TokenReview API that sets the
// spec.audiences field should validate that a compatible audience identifier
// is returned in the status.audiences field to ensure that the TokenReview
// server is audience aware. If a TokenReview returns an empty
// status.audience field where status.authenticated is "true", the token is
// valid against the audience of the Kubernetes API server.
// +optional
Audiences []string `json:"audiences,omitempty" protobuf:"bytes,4,rep,name=audiences"`
// Error indicates that the token couldn't be checked // Error indicates that the token couldn't be checked
// +optional // +optional
Error string `json:"error,omitempty" protobuf:"bytes,3,opt,name=error"` Error string `json:"error,omitempty" protobuf:"bytes,3,opt,name=error"`

View File

@ -81,6 +81,7 @@ func (TokenReview) SwaggerDoc() map[string]string {
var map_TokenReviewSpec = map[string]string{ var map_TokenReviewSpec = map[string]string{
"": "TokenReviewSpec is a description of the token authentication request.", "": "TokenReviewSpec is a description of the token authentication request.",
"token": "Token is the opaque bearer token.", "token": "Token is the opaque bearer token.",
"audiences": "Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver.",
} }
func (TokenReviewSpec) SwaggerDoc() map[string]string { func (TokenReviewSpec) SwaggerDoc() map[string]string {
@ -91,6 +92,7 @@ var map_TokenReviewStatus = map[string]string{
"": "TokenReviewStatus is the result of the token authentication request.", "": "TokenReviewStatus is the result of the token authentication request.",
"authenticated": "Authenticated indicates that the token was associated with a known user.", "authenticated": "Authenticated indicates that the token was associated with a known user.",
"user": "User is the UserInfo associated with the provided token.", "user": "User is the UserInfo associated with the provided token.",
"audiences": "Audiences are audience identifiers chosen by the authenticator that are compatible with both the TokenReview and token. An identifier is any identifier in the intersection of the TokenReviewSpec audiences and the token's audiences. A client of the TokenReview API that sets the spec.audiences field should validate that a compatible audience identifier is returned in the status.audiences field to ensure that the TokenReview server is audience aware. If a TokenReview returns an empty status.audience field where status.authenticated is \"true\", the token is valid against the audience of the Kubernetes API server.",
"error": "Error indicates that the token couldn't be checked", "error": "Error indicates that the token couldn't be checked",
} }

View File

@ -141,7 +141,7 @@ func (in *TokenReview) DeepCopyInto(out *TokenReview) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status) in.Status.DeepCopyInto(&out.Status)
return return
} }
@ -167,6 +167,11 @@ func (in *TokenReview) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TokenReviewSpec) DeepCopyInto(out *TokenReviewSpec) { func (in *TokenReviewSpec) DeepCopyInto(out *TokenReviewSpec) {
*out = *in *out = *in
if in.Audiences != nil {
in, out := &in.Audiences, &out.Audiences
*out = make([]string, len(*in))
copy(*out, *in)
}
return return
} }
@ -184,6 +189,11 @@ func (in *TokenReviewSpec) DeepCopy() *TokenReviewSpec {
func (in *TokenReviewStatus) DeepCopyInto(out *TokenReviewStatus) { func (in *TokenReviewStatus) DeepCopyInto(out *TokenReviewStatus) {
*out = *in *out = *in
in.User.DeepCopyInto(&out.User) in.User.DeepCopyInto(&out.User)
if in.Audiences != nil {
in, out := &in.Audiences, &out.Audiences
*out = make([]string, len(*in))
copy(*out, *in)
}
return return
} }

View File

@ -175,6 +175,21 @@ func (m *TokenReviewSpec) MarshalTo(dAtA []byte) (int, error) {
i++ i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Token))) i = encodeVarintGenerated(dAtA, i, uint64(len(m.Token)))
i += copy(dAtA[i:], m.Token) i += copy(dAtA[i:], m.Token)
if len(m.Audiences) > 0 {
for _, s := range m.Audiences {
dAtA[i] = 0x12
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil return i, nil
} }
@ -213,6 +228,21 @@ func (m *TokenReviewStatus) MarshalTo(dAtA []byte) (int, error) {
i++ i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Error))) i = encodeVarintGenerated(dAtA, i, uint64(len(m.Error)))
i += copy(dAtA[i:], m.Error) i += copy(dAtA[i:], m.Error)
if len(m.Audiences) > 0 {
for _, s := range m.Audiences {
dAtA[i] = 0x22
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil return i, nil
} }
@ -326,6 +356,12 @@ func (m *TokenReviewSpec) Size() (n int) {
_ = l _ = l
l = len(m.Token) l = len(m.Token)
n += 1 + l + sovGenerated(uint64(l)) n += 1 + l + sovGenerated(uint64(l))
if len(m.Audiences) > 0 {
for _, s := range m.Audiences {
l = len(s)
n += 1 + l + sovGenerated(uint64(l))
}
}
return n return n
} }
@ -337,6 +373,12 @@ func (m *TokenReviewStatus) Size() (n int) {
n += 1 + l + sovGenerated(uint64(l)) n += 1 + l + sovGenerated(uint64(l))
l = len(m.Error) l = len(m.Error)
n += 1 + l + sovGenerated(uint64(l)) n += 1 + l + sovGenerated(uint64(l))
if len(m.Audiences) > 0 {
for _, s := range m.Audiences {
l = len(s)
n += 1 + l + sovGenerated(uint64(l))
}
}
return n return n
} }
@ -396,6 +438,7 @@ func (this *TokenReviewSpec) String() string {
} }
s := strings.Join([]string{`&TokenReviewSpec{`, s := strings.Join([]string{`&TokenReviewSpec{`,
`Token:` + fmt.Sprintf("%v", this.Token) + `,`, `Token:` + fmt.Sprintf("%v", this.Token) + `,`,
`Audiences:` + fmt.Sprintf("%v", this.Audiences) + `,`,
`}`, `}`,
}, "") }, "")
return s return s
@ -408,6 +451,7 @@ func (this *TokenReviewStatus) String() string {
`Authenticated:` + fmt.Sprintf("%v", this.Authenticated) + `,`, `Authenticated:` + fmt.Sprintf("%v", this.Authenticated) + `,`,
`User:` + strings.Replace(strings.Replace(this.User.String(), "UserInfo", "UserInfo", 1), `&`, ``, 1) + `,`, `User:` + strings.Replace(strings.Replace(this.User.String(), "UserInfo", "UserInfo", 1), `&`, ``, 1) + `,`,
`Error:` + fmt.Sprintf("%v", this.Error) + `,`, `Error:` + fmt.Sprintf("%v", this.Error) + `,`,
`Audiences:` + fmt.Sprintf("%v", this.Audiences) + `,`,
`}`, `}`,
}, "") }, "")
return s return s
@ -720,6 +764,35 @@ func (m *TokenReviewSpec) Unmarshal(dAtA []byte) error {
} }
m.Token = string(dAtA[iNdEx:postIndex]) m.Token = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Audiences", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Audiences = append(m.Audiences, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:]) skippy, err := skipGenerated(dAtA[iNdEx:])
@ -849,6 +922,35 @@ func (m *TokenReviewStatus) Unmarshal(dAtA []byte) error {
} }
m.Error = string(dAtA[iNdEx:postIndex]) m.Error = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Audiences", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Audiences = append(m.Audiences, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:]) skippy, err := skipGenerated(dAtA[iNdEx:])
@ -1240,45 +1342,47 @@ func init() {
} }
var fileDescriptorGenerated = []byte{ var fileDescriptorGenerated = []byte{
// 635 bytes of a gzipped FileDescriptorProto // 663 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xcf, 0x4f, 0xd4, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xcd, 0x4e, 0x14, 0x4d,
0x14, 0x6e, 0xf7, 0x07, 0xee, 0xce, 0x8a, 0xe2, 0x24, 0x26, 0x9b, 0x4d, 0xec, 0xae, 0xeb, 0x85, 0x14, 0xed, 0x9e, 0x1f, 0xbe, 0x99, 0x9a, 0x6f, 0x14, 0x2b, 0x31, 0x99, 0x4c, 0x62, 0x0f, 0x8e,
0x44, 0x99, 0x0a, 0x21, 0x48, 0xf0, 0x64, 0x95, 0x18, 0x4c, 0x88, 0xc9, 0x08, 0x1e, 0xd4, 0x83, 0x1b, 0x12, 0xa4, 0x5a, 0x08, 0x41, 0x82, 0x2b, 0x5a, 0x89, 0xc1, 0x84, 0x98, 0x94, 0xe0, 0x42,
0xb3, 0xdd, 0x47, 0xb7, 0xae, 0xed, 0x34, 0xd3, 0x69, 0x95, 0x1b, 0x7f, 0x82, 0x47, 0x8f, 0x26, 0x5d, 0x58, 0xd3, 0x73, 0xe9, 0x69, 0xc7, 0xfe, 0x49, 0x55, 0xf5, 0x28, 0x3b, 0x1e, 0xc1, 0xa5,
0xfe, 0x25, 0x26, 0x1e, 0x38, 0x72, 0xe4, 0x60, 0x88, 0xd4, 0x7f, 0xc4, 0xcc, 0x74, 0x64, 0x17, 0x4b, 0x13, 0x9f, 0xc4, 0x1d, 0x4b, 0x96, 0x2c, 0xcc, 0x44, 0xda, 0x27, 0xf0, 0x0d, 0x4c, 0x55,
0x88, 0x01, 0x6e, 0xf3, 0xbe, 0xf7, 0xbe, 0x6f, 0xde, 0xf7, 0x66, 0x1e, 0x7a, 0x31, 0x5e, 0x4d, 0x17, 0xcc, 0x00, 0x31, 0xc0, 0xae, 0xeb, 0xdc, 0x7b, 0xce, 0x3d, 0xf7, 0x54, 0x17, 0x7a, 0x31,
0x49, 0xc8, 0xdd, 0x71, 0x36, 0x00, 0x11, 0x83, 0x84, 0xd4, 0xcd, 0x21, 0x1e, 0x72, 0xe1, 0x9a, 0x5c, 0x13, 0x24, 0x4c, 0xdc, 0x61, 0xd6, 0x03, 0x1e, 0x83, 0x04, 0xe1, 0x8e, 0x20, 0xee, 0x27,
0x04, 0x4b, 0x42, 0x97, 0x65, 0x72, 0x04, 0xb1, 0x0c, 0x7d, 0x26, 0x43, 0x1e, 0xbb, 0xf9, 0xe2, 0xdc, 0x35, 0x05, 0x96, 0x86, 0x2e, 0xcb, 0xe4, 0x00, 0x62, 0x19, 0xfa, 0x4c, 0x86, 0x49, 0xec,
0x00, 0x24, 0x5b, 0x74, 0x03, 0x88, 0x41, 0x30, 0x09, 0x43, 0x92, 0x08, 0x2e, 0x39, 0xbe, 0x5b, 0x8e, 0x96, 0x7a, 0x20, 0xd9, 0x92, 0x1b, 0x40, 0x0c, 0x9c, 0x49, 0xe8, 0x93, 0x94, 0x27, 0x32,
0x52, 0x08, 0x4b, 0x42, 0x72, 0x9a, 0x42, 0x0c, 0xa5, 0xb3, 0x10, 0x84, 0x72, 0x94, 0x0d, 0x88, 0xc1, 0xf7, 0x0b, 0x0a, 0x61, 0x69, 0x48, 0xce, 0x53, 0x88, 0xa1, 0xb4, 0x17, 0x83, 0x50, 0x0e,
0xcf, 0x23, 0x37, 0xe0, 0x01, 0x77, 0x35, 0x73, 0x90, 0xed, 0xe8, 0x48, 0x07, 0xfa, 0x54, 0x2a, 0xb2, 0x1e, 0xf1, 0x93, 0xc8, 0x0d, 0x92, 0x20, 0x71, 0x35, 0xb3, 0x97, 0xed, 0xe9, 0x93, 0x3e,
0x76, 0x96, 0x27, 0x4d, 0x44, 0xcc, 0x1f, 0x85, 0x31, 0x88, 0x5d, 0x37, 0x19, 0x07, 0x0a, 0x48, 0xe8, 0xaf, 0x42, 0xb1, 0xbd, 0x32, 0x31, 0x11, 0x31, 0x7f, 0x10, 0xc6, 0xc0, 0xf7, 0xdd, 0x74,
0xdd, 0x08, 0x24, 0x73, 0xf3, 0x73, 0x7d, 0x74, 0xdc, 0xff, 0xb1, 0x44, 0x16, 0xcb, 0x30, 0x82, 0x18, 0x28, 0x40, 0xb8, 0x11, 0x48, 0xe6, 0x8e, 0x2e, 0xf9, 0x68, 0xbb, 0xff, 0x62, 0xf1, 0x2c,
0x73, 0x84, 0x95, 0x8b, 0x08, 0xa9, 0x3f, 0x82, 0x88, 0x9d, 0xe5, 0xf5, 0x1f, 0x21, 0xb4, 0xfe, 0x96, 0x61, 0x04, 0x97, 0x08, 0xab, 0x57, 0x11, 0x84, 0x3f, 0x80, 0x88, 0x5d, 0xe4, 0x75, 0x1f,
0x59, 0x0a, 0xf6, 0x9a, 0x7d, 0xcc, 0x00, 0x77, 0x51, 0x3d, 0x94, 0x10, 0xa5, 0x6d, 0xbb, 0x57, 0x23, 0xb4, 0xf9, 0x59, 0x72, 0xf6, 0x9a, 0x7d, 0xcc, 0x00, 0x77, 0x50, 0x35, 0x94, 0x10, 0x89,
0x9d, 0x6f, 0x7a, 0xcd, 0xe2, 0xa8, 0x5b, 0xdf, 0x50, 0x00, 0x2d, 0xf1, 0xb5, 0xc6, 0xd7, 0x6f, 0x96, 0x3d, 0x57, 0x9e, 0xaf, 0x7b, 0xf5, 0x7c, 0xdc, 0xa9, 0x6e, 0x29, 0x80, 0x16, 0xf8, 0x7a,
0x5d, 0x6b, 0xef, 0x57, 0xcf, 0xea, 0x7f, 0xaf, 0xa0, 0xd6, 0x16, 0x1f, 0x43, 0x4c, 0x21, 0x0f, 0xed, 0xeb, 0xb7, 0x8e, 0x75, 0xf0, 0x73, 0xce, 0xea, 0x7e, 0x2f, 0xa1, 0xc6, 0x4e, 0x32, 0x84,
0xe1, 0x13, 0x7e, 0x8f, 0x1a, 0xca, 0xcc, 0x90, 0x49, 0xd6, 0xb6, 0x7b, 0xf6, 0x7c, 0x6b, 0xe9, 0x98, 0xc2, 0x28, 0x84, 0x4f, 0xf8, 0x3d, 0xaa, 0xa9, 0x65, 0xfa, 0x4c, 0xb2, 0x96, 0x3d, 0x67,
0x21, 0x99, 0x0c, 0xf3, 0xa4, 0x27, 0x92, 0x8c, 0x03, 0x05, 0xa4, 0x44, 0x55, 0x93, 0x7c, 0x91, 0xcf, 0x37, 0x96, 0x1f, 0x91, 0x49, 0x98, 0x67, 0x9e, 0x48, 0x3a, 0x0c, 0x14, 0x20, 0x88, 0xea,
0xbc, 0x1c, 0x7c, 0x00, 0x5f, 0x6e, 0x82, 0x64, 0x1e, 0xde, 0x3f, 0xea, 0x5a, 0xc5, 0x51, 0x17, 0x26, 0xa3, 0x25, 0xf2, 0xb2, 0xf7, 0x01, 0x7c, 0xb9, 0x0d, 0x92, 0x79, 0xf8, 0x70, 0xdc, 0xb1,
0x4d, 0x30, 0x7a, 0xa2, 0x8a, 0xb7, 0x50, 0x2d, 0x4d, 0xc0, 0x6f, 0x57, 0xb4, 0xfa, 0x12, 0xb9, 0xf2, 0x71, 0x07, 0x4d, 0x30, 0x7a, 0xa6, 0x8a, 0x77, 0x50, 0x45, 0xa4, 0xe0, 0xb7, 0x4a, 0x5a,
0xf0, 0xa9, 0xc8, 0x54, 0x7f, 0xaf, 0x12, 0xf0, 0xbd, 0xeb, 0x46, 0xbf, 0xa6, 0x22, 0xaa, 0xd5, 0x7d, 0x99, 0x5c, 0x79, 0x55, 0x64, 0xca, 0xdf, 0xab, 0x14, 0x7c, 0xef, 0x7f, 0xa3, 0x5f, 0x51,
0xf0, 0x3b, 0x34, 0x93, 0x4a, 0x26, 0xb3, 0xb4, 0x5d, 0xd5, 0xba, 0xcb, 0x57, 0xd4, 0xd5, 0x5c, 0x27, 0xaa, 0xd5, 0xf0, 0x3b, 0x34, 0x23, 0x24, 0x93, 0x99, 0x68, 0x95, 0xb5, 0xee, 0xca, 0x0d,
0xef, 0x86, 0x51, 0x9e, 0x29, 0x63, 0x6a, 0x34, 0xfb, 0x2b, 0xe8, 0xe6, 0x99, 0x26, 0xf0, 0x3d, 0x75, 0x35, 0xd7, 0xbb, 0x65, 0x94, 0x67, 0x8a, 0x33, 0x35, 0x9a, 0x5d, 0x1f, 0xdd, 0xbe, 0x60,
0x54, 0x97, 0x0a, 0xd2, 0x53, 0x6a, 0x7a, 0xb3, 0x86, 0x59, 0x2f, 0xeb, 0xca, 0x5c, 0xff, 0xa7, 0x02, 0x3f, 0x40, 0x55, 0xa9, 0x20, 0x9d, 0x52, 0xdd, 0x6b, 0x1a, 0x66, 0xb5, 0xe8, 0x2b, 0x6a,
0x8d, 0x6e, 0x9d, 0xbb, 0x05, 0x3f, 0x46, 0xb3, 0x53, 0x1d, 0xc1, 0x50, 0x4b, 0x34, 0xbc, 0xdb, 0x78, 0x01, 0xd5, 0x59, 0xd6, 0x0f, 0x21, 0xf6, 0x41, 0xb4, 0x4a, 0xfa, 0x32, 0x9a, 0xf9, 0xb8,
0x46, 0x62, 0xf6, 0xc9, 0x74, 0x92, 0x9e, 0xae, 0xc5, 0x9b, 0xa8, 0x96, 0xa5, 0x20, 0xcc, 0xf8, 0x53, 0xdf, 0x38, 0x05, 0xe9, 0xa4, 0xde, 0xfd, 0x63, 0xa3, 0x3b, 0x97, 0x2c, 0xe1, 0x27, 0xa8,
0xee, 0x5f, 0xc2, 0xe6, 0x76, 0x0a, 0x62, 0x23, 0xde, 0xe1, 0x93, 0xb9, 0x29, 0x84, 0x6a, 0x19, 0x39, 0x65, 0x1f, 0xfa, 0x7a, 0x5e, 0xcd, 0xbb, 0x6b, 0xe6, 0x35, 0x37, 0xa6, 0x8b, 0xf4, 0x7c,
0x65, 0x03, 0x84, 0xe0, 0x42, 0x8f, 0x6d, 0xca, 0xc6, 0xba, 0x02, 0x69, 0x99, 0xeb, 0xff, 0xa8, 0x2f, 0xde, 0x46, 0x95, 0x4c, 0x00, 0x37, 0x59, 0x2f, 0x5c, 0x23, 0x93, 0x5d, 0x01, 0x7c, 0x2b,
0xa0, 0xc6, 0x3f, 0x15, 0xfc, 0x00, 0x35, 0x14, 0x33, 0x66, 0x11, 0x18, 0xef, 0x73, 0x86, 0xa4, 0xde, 0x4b, 0x26, 0x21, 0x2b, 0x84, 0x6a, 0x19, 0xb5, 0x33, 0x70, 0x9e, 0x70, 0x9d, 0xf1, 0xd4,
0x6b, 0x14, 0x4e, 0x4f, 0x2a, 0xf0, 0x1d, 0x54, 0xcd, 0xc2, 0xa1, 0xee, 0xb6, 0xe9, 0xb5, 0x4c, 0xce, 0x9b, 0x0a, 0xa4, 0x45, 0xed, 0xfc, 0xce, 0x95, 0x2b, 0x76, 0xfe, 0x51, 0x42, 0xb5, 0xd3,
0x61, 0x75, 0x7b, 0xe3, 0x19, 0x55, 0x38, 0xee, 0xa3, 0x99, 0x40, 0xf0, 0x2c, 0x51, 0xcf, 0xa6, 0x91, 0xf8, 0x21, 0xaa, 0xa9, 0x31, 0x31, 0x8b, 0xc0, 0xa4, 0x3a, 0x6b, 0x26, 0xe8, 0x1e, 0x85,
0xbe, 0x2a, 0x52, 0xc3, 0x7f, 0xae, 0x11, 0x6a, 0x32, 0xf8, 0x2d, 0xaa, 0x83, 0xfa, 0xdb, 0xed, 0xd3, 0xb3, 0x0e, 0x7c, 0x0f, 0x95, 0xb3, 0xb0, 0xaf, 0x57, 0xab, 0x7b, 0x0d, 0xd3, 0x58, 0xde,
0x5a, 0xaf, 0x3a, 0xdf, 0x5a, 0x5a, 0xb9, 0x82, 0x65, 0xa2, 0x97, 0x62, 0x3d, 0x96, 0x62, 0x77, 0xdd, 0x7a, 0x46, 0x15, 0x8e, 0xbb, 0x68, 0x26, 0xe0, 0x49, 0x96, 0xaa, 0x1f, 0x42, 0x79, 0x40,
0xca, 0x9a, 0xc2, 0x68, 0xa9, 0xd9, 0x09, 0xcc, 0xe2, 0xe8, 0x1a, 0x3c, 0x87, 0xaa, 0x63, 0xd8, 0xea, 0x5a, 0x9f, 0x6b, 0x84, 0x9a, 0x0a, 0x7e, 0x8b, 0xaa, 0xa0, 0x5e, 0x8d, 0xb6, 0xd9, 0x58,
0x2d, 0x6d, 0x51, 0x75, 0xc4, 0x4f, 0x51, 0x3d, 0x57, 0x3b, 0x65, 0xe6, 0xbd, 0x70, 0x89, 0xcb, 0x5e, 0xbd, 0x41, 0x3e, 0x44, 0x3f, 0xb7, 0xcd, 0x58, 0xf2, 0xfd, 0xa9, 0x1c, 0x14, 0x46, 0x0b,
0x27, 0x8b, 0x48, 0x4b, 0xee, 0x5a, 0x65, 0xd5, 0xf6, 0x16, 0xf6, 0x8f, 0x1d, 0xeb, 0xe0, 0xd8, 0xcd, 0x76, 0x60, 0x9e, 0xa4, 0xee, 0xc1, 0xb3, 0xa8, 0x3c, 0x84, 0xfd, 0x62, 0x2d, 0xaa, 0x3e,
0xb1, 0x0e, 0x8f, 0x1d, 0x6b, 0xaf, 0x70, 0xec, 0xfd, 0xc2, 0xb1, 0x0f, 0x0a, 0xc7, 0x3e, 0x2c, 0xf1, 0x53, 0x54, 0x1d, 0xa9, 0xd7, 0x6a, 0x2e, 0x67, 0xf1, 0x1a, 0xc3, 0x27, 0x4f, 0x9c, 0x16,
0x1c, 0xfb, 0x77, 0xe1, 0xd8, 0x5f, 0xfe, 0x38, 0xd6, 0x9b, 0x6b, 0x46, 0xe4, 0x6f, 0x00, 0x00, 0xdc, 0xf5, 0xd2, 0x9a, 0xed, 0x2d, 0x1e, 0x9e, 0x38, 0xd6, 0xd1, 0x89, 0x63, 0x1d, 0x9f, 0x38,
0x00, 0xff, 0xff, 0x39, 0x00, 0xe7, 0xfa, 0x0e, 0x05, 0x00, 0x00, 0xd6, 0x41, 0xee, 0xd8, 0x87, 0xb9, 0x63, 0x1f, 0xe5, 0x8e, 0x7d, 0x9c, 0x3b, 0xf6, 0xaf, 0xdc,
0xb1, 0xbf, 0xfc, 0x76, 0xac, 0x37, 0xff, 0x19, 0x91, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf7,
0xd6, 0x32, 0x28, 0x68, 0x05, 0x00, 0x00,
} }

View File

@ -57,6 +57,14 @@ message TokenReviewSpec {
// Token is the opaque bearer token. // Token is the opaque bearer token.
// +optional // +optional
optional string token = 1; optional string token = 1;
// Audiences is a list of the identifiers that the resource server presented
// with the token identifies as. Audience-aware token authenticators will
// verify that the token was intended for at least one of the audiences in
// this list. If no audiences are provided, the audience will default to the
// audience of the Kubernetes apiserver.
// +optional
repeated string audiences = 2;
} }
// TokenReviewStatus is the result of the token authentication request. // TokenReviewStatus is the result of the token authentication request.
@ -69,6 +77,18 @@ message TokenReviewStatus {
// +optional // +optional
optional UserInfo user = 2; optional UserInfo user = 2;
// Audiences are audience identifiers chosen by the authenticator that are
// compatible with both the TokenReview and token. An identifier is any
// identifier in the intersection of the TokenReviewSpec audiences and the
// token's audiences. A client of the TokenReview API that sets the
// spec.audiences field should validate that a compatible audience identifier
// is returned in the status.audiences field to ensure that the TokenReview
// server is audience aware. If a TokenReview returns an empty
// status.audience field where status.authenticated is "true", the token is
// valid against the audience of the Kubernetes API server.
// +optional
repeated string audiences = 4;
// Error indicates that the token couldn't be checked // Error indicates that the token couldn't be checked
// +optional // +optional
optional string error = 3; optional string error = 3;

View File

@ -48,6 +48,13 @@ type TokenReviewSpec struct {
// Token is the opaque bearer token. // Token is the opaque bearer token.
// +optional // +optional
Token string `json:"token,omitempty" protobuf:"bytes,1,opt,name=token"` Token string `json:"token,omitempty" protobuf:"bytes,1,opt,name=token"`
// Audiences is a list of the identifiers that the resource server presented
// with the token identifies as. Audience-aware token authenticators will
// verify that the token was intended for at least one of the audiences in
// this list. If no audiences are provided, the audience will default to the
// audience of the Kubernetes apiserver.
// +optional
Audiences []string `json:"audiences,omitempty" protobuf:"bytes,2,rep,name=audiences"`
} }
// TokenReviewStatus is the result of the token authentication request. // TokenReviewStatus is the result of the token authentication request.
@ -58,6 +65,17 @@ type TokenReviewStatus struct {
// User is the UserInfo associated with the provided token. // User is the UserInfo associated with the provided token.
// +optional // +optional
User UserInfo `json:"user,omitempty" protobuf:"bytes,2,opt,name=user"` User UserInfo `json:"user,omitempty" protobuf:"bytes,2,opt,name=user"`
// Audiences are audience identifiers chosen by the authenticator that are
// compatible with both the TokenReview and token. An identifier is any
// identifier in the intersection of the TokenReviewSpec audiences and the
// token's audiences. A client of the TokenReview API that sets the
// spec.audiences field should validate that a compatible audience identifier
// is returned in the status.audiences field to ensure that the TokenReview
// server is audience aware. If a TokenReview returns an empty
// status.audience field where status.authenticated is "true", the token is
// valid against the audience of the Kubernetes API server.
// +optional
Audiences []string `json:"audiences,omitempty" protobuf:"bytes,4,rep,name=audiences"`
// Error indicates that the token couldn't be checked // Error indicates that the token couldn't be checked
// +optional // +optional
Error string `json:"error,omitempty" protobuf:"bytes,3,opt,name=error"` Error string `json:"error,omitempty" protobuf:"bytes,3,opt,name=error"`

View File

@ -40,6 +40,7 @@ func (TokenReview) SwaggerDoc() map[string]string {
var map_TokenReviewSpec = map[string]string{ var map_TokenReviewSpec = map[string]string{
"": "TokenReviewSpec is a description of the token authentication request.", "": "TokenReviewSpec is a description of the token authentication request.",
"token": "Token is the opaque bearer token.", "token": "Token is the opaque bearer token.",
"audiences": "Audiences is a list of the identifiers that the resource server presented with the token identifies as. Audience-aware token authenticators will verify that the token was intended for at least one of the audiences in this list. If no audiences are provided, the audience will default to the audience of the Kubernetes apiserver.",
} }
func (TokenReviewSpec) SwaggerDoc() map[string]string { func (TokenReviewSpec) SwaggerDoc() map[string]string {
@ -50,6 +51,7 @@ var map_TokenReviewStatus = map[string]string{
"": "TokenReviewStatus is the result of the token authentication request.", "": "TokenReviewStatus is the result of the token authentication request.",
"authenticated": "Authenticated indicates that the token was associated with a known user.", "authenticated": "Authenticated indicates that the token was associated with a known user.",
"user": "User is the UserInfo associated with the provided token.", "user": "User is the UserInfo associated with the provided token.",
"audiences": "Audiences are audience identifiers chosen by the authenticator that are compatible with both the TokenReview and token. An identifier is any identifier in the intersection of the TokenReviewSpec audiences and the token's audiences. A client of the TokenReview API that sets the spec.audiences field should validate that a compatible audience identifier is returned in the status.audiences field to ensure that the TokenReview server is audience aware. If a TokenReview returns an empty status.audience field where status.authenticated is \"true\", the token is valid against the audience of the Kubernetes API server.",
"error": "Error indicates that the token couldn't be checked", "error": "Error indicates that the token couldn't be checked",
} }

View File

@ -49,7 +49,7 @@ func (in *TokenReview) DeepCopyInto(out *TokenReview) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status) in.Status.DeepCopyInto(&out.Status)
return return
} }
@ -75,6 +75,11 @@ func (in *TokenReview) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TokenReviewSpec) DeepCopyInto(out *TokenReviewSpec) { func (in *TokenReviewSpec) DeepCopyInto(out *TokenReviewSpec) {
*out = *in *out = *in
if in.Audiences != nil {
in, out := &in.Audiences, &out.Audiences
*out = make([]string, len(*in))
copy(*out, *in)
}
return return
} }
@ -92,6 +97,11 @@ func (in *TokenReviewSpec) DeepCopy() *TokenReviewSpec {
func (in *TokenReviewStatus) DeepCopyInto(out *TokenReviewStatus) { func (in *TokenReviewStatus) DeepCopyInto(out *TokenReviewStatus) {
*out = *in *out = *in
in.User.DeepCopyInto(&out.User) in.User.DeepCopyInto(&out.User)
if in.Audiences != nil {
in, out := &in.Audiences, &out.Audiences
*out = make([]string, len(*in))
copy(*out, *in)
}
return return
} }

View File

@ -51,6 +51,8 @@ type DelegatingAuthenticatorConfig struct {
// ClientCAFile is the CA bundle file used to authenticate client certificates // ClientCAFile is the CA bundle file used to authenticate client certificates
ClientCAFile string ClientCAFile string
APIAudiences authenticator.Audiences
RequestHeaderConfig *RequestHeaderConfig RequestHeaderConfig *RequestHeaderConfig
} }
@ -86,7 +88,7 @@ func (c DelegatingAuthenticatorConfig) New() (authenticator.Request, *spec.Secur
} }
if c.TokenAccessReviewClient != nil { if c.TokenAccessReviewClient != nil {
tokenAuth, err := webhooktoken.NewFromInterface(c.TokenAccessReviewClient) tokenAuth, err := webhooktoken.NewFromInterface(c.TokenAccessReviewClient, c.APIAudiences)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@ -21,8 +21,6 @@ import (
"context" "context"
"time" "time"
"k8s.io/klog"
authentication "k8s.io/api/authentication/v1beta1" authentication "k8s.io/api/authentication/v1beta1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@ -31,6 +29,7 @@ import (
"k8s.io/apiserver/pkg/util/webhook" "k8s.io/apiserver/pkg/util/webhook"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1beta1" authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1beta1"
"k8s.io/klog"
) )
var ( var (
@ -45,38 +44,58 @@ var _ authenticator.Token = (*WebhookTokenAuthenticator)(nil)
type WebhookTokenAuthenticator struct { type WebhookTokenAuthenticator struct {
tokenReview authenticationclient.TokenReviewInterface tokenReview authenticationclient.TokenReviewInterface
initialBackoff time.Duration initialBackoff time.Duration
implicitAuds authenticator.Audiences
} }
// NewFromInterface creates a webhook authenticator using the given tokenReview // NewFromInterface creates a webhook authenticator using the given tokenReview
// client. It is recommend to wrap this authenticator with the token cache // client. It is recommend to wrap this authenticator with the token cache
// authenticator implemented in // authenticator implemented in
// k8s.io/apiserver/pkg/authentication/token/cache. // k8s.io/apiserver/pkg/authentication/token/cache.
func NewFromInterface(tokenReview authenticationclient.TokenReviewInterface) (*WebhookTokenAuthenticator, error) { func NewFromInterface(tokenReview authenticationclient.TokenReviewInterface, implicitAuds authenticator.Audiences) (*WebhookTokenAuthenticator, error) {
return newWithBackoff(tokenReview, retryBackoff) return newWithBackoff(tokenReview, retryBackoff, implicitAuds)
} }
// New creates a new WebhookTokenAuthenticator from the provided kubeconfig file. // New creates a new WebhookTokenAuthenticator from the provided kubeconfig
func New(kubeConfigFile string) (*WebhookTokenAuthenticator, error) { // file. It is recommend to wrap this authenticator with the token cache
// authenticator implemented in
// k8s.io/apiserver/pkg/authentication/token/cache.
func New(kubeConfigFile string, implicitAuds authenticator.Audiences) (*WebhookTokenAuthenticator, error) {
tokenReview, err := tokenReviewInterfaceFromKubeconfig(kubeConfigFile) tokenReview, err := tokenReviewInterfaceFromKubeconfig(kubeConfigFile)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newWithBackoff(tokenReview, retryBackoff) return newWithBackoff(tokenReview, retryBackoff, implicitAuds)
} }
// newWithBackoff allows tests to skip the sleep. // newWithBackoff allows tests to skip the sleep.
func newWithBackoff(tokenReview authenticationclient.TokenReviewInterface, initialBackoff time.Duration) (*WebhookTokenAuthenticator, error) { func newWithBackoff(tokenReview authenticationclient.TokenReviewInterface, initialBackoff time.Duration, implicitAuds authenticator.Audiences) (*WebhookTokenAuthenticator, error) {
return &WebhookTokenAuthenticator{tokenReview, initialBackoff}, nil return &WebhookTokenAuthenticator{tokenReview, initialBackoff, implicitAuds}, nil
} }
// AuthenticateToken implements the authenticator.Token interface. // AuthenticateToken implements the authenticator.Token interface.
func (w *WebhookTokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) { func (w *WebhookTokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
// We take implicit audiences of the API server at WebhookTokenAuthenticator
// construction time. The outline of how we validate audience here is:
//
// * if the ctx is not audience limited, don't do any audience validation.
// * if ctx is audience-limited, add the audiences to the tokenreview spec
// * if the tokenreview returns with audiences in the status that intersect
// with the audiences in the ctx, copy into the response and return success
// * if the tokenreview returns without an audience in the status, ensure
// the ctx audiences intersect with the implicit audiences, and set the
// intersection in the response.
// * otherwise return unauthenticated.
wantAuds, checkAuds := authenticator.AudiencesFrom(ctx)
r := &authentication.TokenReview{ r := &authentication.TokenReview{
Spec: authentication.TokenReviewSpec{Token: token}, Spec: authentication.TokenReviewSpec{
Token: token,
Audiences: wantAuds,
},
} }
var ( var (
result *authentication.TokenReview result *authentication.TokenReview
err error err error
auds authenticator.Audiences
) )
webhook.WithExponentialBackoff(w.initialBackoff, func() error { webhook.WithExponentialBackoff(w.initialBackoff, func() error {
result, err = w.tokenReview.Create(r) result, err = w.tokenReview.Create(r)
@ -87,6 +106,18 @@ func (w *WebhookTokenAuthenticator) AuthenticateToken(ctx context.Context, token
klog.Errorf("Failed to make webhook authenticator request: %v", err) klog.Errorf("Failed to make webhook authenticator request: %v", err)
return nil, false, err return nil, false, err
} }
if checkAuds {
gotAuds := w.implicitAuds
if len(result.Status.Audiences) > 0 {
gotAuds = result.Status.Audiences
}
auds = wantAuds.Intersect(gotAuds)
if len(auds) == 0 {
return nil, false, nil
}
}
r.Status = result.Status r.Status = result.Status
if !r.Status.Authenticated { if !r.Status.Authenticated {
return nil, false, nil return nil, false, nil
@ -107,6 +138,7 @@ func (w *WebhookTokenAuthenticator) AuthenticateToken(ctx context.Context, token
Groups: r.Status.User.Groups, Groups: r.Status.User.Groups,
Extra: extra, Extra: extra,
}, },
Audiences: auds,
}, true, nil }, true, nil
} }

View File

@ -39,6 +39,8 @@ import (
"k8s.io/client-go/tools/clientcmd/api/v1" "k8s.io/client-go/tools/clientcmd/api/v1"
) )
var apiAuds = authenticator.Audiences{"api"}
// Service mocks a remote authentication service. // Service mocks a remote authentication service.
type Service interface { type Service interface {
// Review looks at the TokenReviewSpec and provides an authentication // Review looks at the TokenReviewSpec and provides an authentication
@ -105,6 +107,7 @@ func NewTestServer(s Service, cert, key, caCert []byte) (*httptest.Server, error
type status struct { type status struct {
Authenticated bool `json:"authenticated"` Authenticated bool `json:"authenticated"`
User userInfo `json:"user"` User userInfo `json:"user"`
Audiences []string `json:"audiences"`
} }
var extra map[string][]string var extra map[string][]string
@ -130,6 +133,7 @@ func NewTestServer(s Service, cert, key, caCert []byte) (*httptest.Server, error
Groups: review.Status.User.Groups, Groups: review.Status.User.Groups,
Extra: extra, Extra: extra,
}, },
review.Status.Audiences,
}, },
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@ -168,7 +172,7 @@ func (m *mockService) HTTPStatusCode() int { return m.statusCode }
// newTokenAuthenticator creates a temporary kubeconfig file from the provided // newTokenAuthenticator creates a temporary kubeconfig file from the provided
// arguments and attempts to load a new WebhookTokenAuthenticator from it. // arguments and attempts to load a new WebhookTokenAuthenticator from it.
func newTokenAuthenticator(serverURL string, clientCert, clientKey, ca []byte, cacheTime time.Duration) (authenticator.Token, error) { func newTokenAuthenticator(serverURL string, clientCert, clientKey, ca []byte, cacheTime time.Duration, implicitAuds authenticator.Audiences) (authenticator.Token, error) {
tempfile, err := ioutil.TempFile("", "") tempfile, err := ioutil.TempFile("", "")
if err != nil { if err != nil {
return nil, err return nil, err
@ -196,7 +200,7 @@ func newTokenAuthenticator(serverURL string, clientCert, clientKey, ca []byte, c
return nil, err return nil, err
} }
authn, err := newWithBackoff(c, 0) authn, err := newWithBackoff(c, 0, implicitAuds)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -257,7 +261,7 @@ func TestTLSConfig(t *testing.T) {
} }
defer server.Close() defer server.Close()
wh, err := newTokenAuthenticator(server.URL, tt.clientCert, tt.clientKey, tt.clientCA, 0) wh, err := newTokenAuthenticator(server.URL, tt.clientCert, tt.clientKey, tt.clientCA, 0, nil)
if err != nil { if err != nil {
t.Errorf("%s: failed to create client: %v", tt.test, err) t.Errorf("%s: failed to create client: %v", tt.test, err)
return return
@ -312,23 +316,21 @@ func TestWebhookTokenAuthenticator(t *testing.T) {
} }
defer s.Close() defer s.Close()
wh, err := newTokenAuthenticator(s.URL, clientCert, clientKey, caCert, 0)
if err != nil {
t.Fatal(err)
}
expTypeMeta := metav1.TypeMeta{ expTypeMeta := metav1.TypeMeta{
APIVersion: "authentication.k8s.io/v1beta1", APIVersion: "authentication.k8s.io/v1beta1",
Kind: "TokenReview", Kind: "TokenReview",
} }
tests := []struct { tests := []struct {
description string
implicitAuds, reqAuds authenticator.Audiences
serverResponse v1beta1.TokenReviewStatus serverResponse v1beta1.TokenReviewStatus
expectedAuthenticated bool expectedAuthenticated bool
expectedUser *user.DefaultInfo expectedUser *user.DefaultInfo
expectedAuds authenticator.Audiences
}{ }{
// Successful response should pass through all user info.
{ {
description: "successful response should pass through all user info.",
serverResponse: v1beta1.TokenReviewStatus{ serverResponse: v1beta1.TokenReviewStatus{
Authenticated: true, Authenticated: true,
User: v1beta1.UserInfo{ User: v1beta1.UserInfo{
@ -341,6 +343,7 @@ func TestWebhookTokenAuthenticator(t *testing.T) {
}, },
}, },
{ {
description: "successful response should pass through all user info.",
serverResponse: v1beta1.TokenReviewStatus{ serverResponse: v1beta1.TokenReviewStatus{
Authenticated: true, Authenticated: true,
User: v1beta1.UserInfo{ User: v1beta1.UserInfo{
@ -358,8 +361,8 @@ func TestWebhookTokenAuthenticator(t *testing.T) {
Extra: map[string][]string{"foo": {"bar", "baz"}}, Extra: map[string][]string{"foo": {"bar", "baz"}},
}, },
}, },
// Unauthenticated shouldn't even include extra provided info.
{ {
description: "unauthenticated shouldn't even include extra provided info.",
serverResponse: v1beta1.TokenReviewStatus{ serverResponse: v1beta1.TokenReviewStatus{
Authenticated: false, Authenticated: false,
User: v1beta1.UserInfo{ User: v1beta1.UserInfo{
@ -372,37 +375,151 @@ func TestWebhookTokenAuthenticator(t *testing.T) {
expectedUser: nil, expectedUser: nil,
}, },
{ {
description: "unauthenticated shouldn't even include extra provided info.",
serverResponse: v1beta1.TokenReviewStatus{ serverResponse: v1beta1.TokenReviewStatus{
Authenticated: false, Authenticated: false,
}, },
expectedAuthenticated: false, expectedAuthenticated: false,
expectedUser: nil, expectedUser: nil,
}, },
{
description: "good audience",
implicitAuds: apiAuds,
reqAuds: apiAuds,
serverResponse: v1beta1.TokenReviewStatus{
Authenticated: true,
User: v1beta1.UserInfo{
Username: "somebody",
},
},
expectedAuthenticated: true,
expectedUser: &user.DefaultInfo{
Name: "somebody",
},
expectedAuds: apiAuds,
},
{
description: "good audience",
implicitAuds: append(apiAuds, "other"),
reqAuds: apiAuds,
serverResponse: v1beta1.TokenReviewStatus{
Authenticated: true,
User: v1beta1.UserInfo{
Username: "somebody",
},
},
expectedAuthenticated: true,
expectedUser: &user.DefaultInfo{
Name: "somebody",
},
expectedAuds: apiAuds,
},
{
description: "bad audiences",
implicitAuds: apiAuds,
reqAuds: authenticator.Audiences{"other"},
serverResponse: v1beta1.TokenReviewStatus{
Authenticated: false,
},
expectedAuthenticated: false,
},
{
description: "bad audiences",
implicitAuds: apiAuds,
reqAuds: authenticator.Audiences{"other"},
// webhook authenticator hasn't been upgraded to support audience.
serverResponse: v1beta1.TokenReviewStatus{
Authenticated: true,
User: v1beta1.UserInfo{
Username: "somebody",
},
},
expectedAuthenticated: false,
},
{
description: "audience aware backend",
implicitAuds: apiAuds,
reqAuds: apiAuds,
serverResponse: v1beta1.TokenReviewStatus{
Authenticated: true,
User: v1beta1.UserInfo{
Username: "somebody",
},
Audiences: []string(apiAuds),
},
expectedAuthenticated: true,
expectedUser: &user.DefaultInfo{
Name: "somebody",
},
expectedAuds: apiAuds,
},
{
description: "audience aware backend",
serverResponse: v1beta1.TokenReviewStatus{
Authenticated: true,
User: v1beta1.UserInfo{
Username: "somebody",
},
Audiences: []string(apiAuds),
},
expectedAuthenticated: true,
expectedUser: &user.DefaultInfo{
Name: "somebody",
},
},
{
description: "audience aware backend",
implicitAuds: apiAuds,
reqAuds: apiAuds,
serverResponse: v1beta1.TokenReviewStatus{
Authenticated: true,
User: v1beta1.UserInfo{
Username: "somebody",
},
Audiences: []string{"other"},
},
expectedAuthenticated: false,
},
} }
token := "my-s3cr3t-t0ken" token := "my-s3cr3t-t0ken"
for i, tt := range tests { for _, tt := range tests {
serv.response = tt.serverResponse t.Run(tt.description, func(t *testing.T) {
resp, authenticated, err := wh.AuthenticateToken(context.Background(), token) wh, err := newTokenAuthenticator(s.URL, clientCert, clientKey, caCert, 0, tt.implicitAuds)
if err != nil { if err != nil {
t.Errorf("case %d: authentication failed: %v", i, err) t.Fatal(err)
continue }
ctx := context.Background()
if tt.reqAuds != nil {
ctx = authenticator.WithAudiences(ctx, tt.reqAuds)
}
serv.response = tt.serverResponse
resp, authenticated, err := wh.AuthenticateToken(ctx, token)
if err != nil {
t.Fatalf("authentication failed: %v", err)
} }
if serv.lastRequest.Spec.Token != token { if serv.lastRequest.Spec.Token != token {
t.Errorf("case %d: Server did not see correct token. Got %q, expected %q.", t.Errorf("Server did not see correct token. Got %q, expected %q.",
i, serv.lastRequest.Spec.Token, token) serv.lastRequest.Spec.Token, token)
} }
if !reflect.DeepEqual(serv.lastRequest.TypeMeta, expTypeMeta) { if !reflect.DeepEqual(serv.lastRequest.TypeMeta, expTypeMeta) {
t.Errorf("case %d: Server did not see correct TypeMeta. Got %v, expected %v", t.Errorf("Server did not see correct TypeMeta. Got %v, expected %v",
i, serv.lastRequest.TypeMeta, expTypeMeta) serv.lastRequest.TypeMeta, expTypeMeta)
} }
if authenticated != tt.expectedAuthenticated { if authenticated != tt.expectedAuthenticated {
t.Errorf("case %d: Plugin returned incorrect authentication response. Got %t, expected %t.", t.Errorf("Plugin returned incorrect authentication response. Got %t, expected %t.",
i, authenticated, tt.expectedAuthenticated) authenticated, tt.expectedAuthenticated)
} }
if resp != nil && tt.expectedUser != nil && !reflect.DeepEqual(resp.User, tt.expectedUser) { if resp != nil && tt.expectedUser != nil && !reflect.DeepEqual(resp.User, tt.expectedUser) {
t.Errorf("case %d: Plugin returned incorrect user. Got %#v, expected %#v", t.Errorf("Plugin returned incorrect user. Got %#v, expected %#v",
i, resp.User, tt.expectedUser) resp.User, tt.expectedUser)
} }
if resp != nil && tt.expectedAuds != nil && !reflect.DeepEqual(resp.Audiences, tt.expectedAuds) {
t.Errorf("Plugin returned incorrect audiences. Got %#v, expected %#v",
resp.Audiences, tt.expectedAuds)
}
})
} }
} }
@ -440,7 +557,7 @@ func TestWebhookCacheAndRetry(t *testing.T) {
defer s.Close() defer s.Close()
// Create an authenticator that caches successful responses "forever" (100 days). // Create an authenticator that caches successful responses "forever" (100 days).
wh, err := newTokenAuthenticator(s.URL, clientCert, clientKey, caCert, 2400*time.Hour) wh, err := newTokenAuthenticator(s.URL, clientCert, clientKey, caCert, 2400*time.Hour, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -85,7 +85,7 @@ func getTestWebhookTokenAuth(serverURL string) (authenticator.Request, error) {
if err := json.NewEncoder(kubecfgFile).Encode(config); err != nil { if err := json.NewEncoder(kubecfgFile).Encode(config); err != nil {
return nil, err return nil, err
} }
webhookTokenAuth, err := webhook.New(kubecfgFile.Name()) webhookTokenAuth, err := webhook.New(kubecfgFile.Name(), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }