summaryrefslogtreecommitdiff
path: root/vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go')
-rw-r--r--vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go186
1 files changed, 186 insertions, 0 deletions
diff --git a/vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go b/vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go
new file mode 100644
index 000000000..c3ed29c4c
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/serviceaccount/claims.go
@@ -0,0 +1,186 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package serviceaccount
+
+import (
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/golang/glog"
+ apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
+ "k8s.io/kubernetes/pkg/apis/core"
+
+ "gopkg.in/square/go-jose.v2/jwt"
+)
+
+// time.Now stubbed out to allow testing
+var now = time.Now
+
+type privateClaims struct {
+ Kubernetes kubernetes `json:"kubernetes.io,omitempty"`
+}
+
+type kubernetes struct {
+ Namespace string `json:"namespace,omitempty"`
+ Svcacct ref `json:"serviceaccount,omitempty"`
+ Pod *ref `json:"pod,omitempty"`
+ Secret *ref `json:"secret,omitempty"`
+}
+
+type ref struct {
+ Name string `json:"name,omitempty"`
+ UID string `json:"uid,omitempty"`
+}
+
+func Claims(sa core.ServiceAccount, pod *core.Pod, secret *core.Secret, expirationSeconds int64, audience []string) (*jwt.Claims, interface{}) {
+ now := now()
+ sc := &jwt.Claims{
+ Subject: apiserverserviceaccount.MakeUsername(sa.Namespace, sa.Name),
+ Audience: jwt.Audience(audience),
+ IssuedAt: jwt.NewNumericDate(now),
+ NotBefore: jwt.NewNumericDate(now),
+ Expiry: jwt.NewNumericDate(now.Add(time.Duration(expirationSeconds) * time.Second)),
+ }
+ pc := &privateClaims{
+ Kubernetes: kubernetes{
+ Namespace: sa.Namespace,
+ Svcacct: ref{
+ Name: sa.Name,
+ UID: string(sa.UID),
+ },
+ },
+ }
+ switch {
+ case pod != nil:
+ pc.Kubernetes.Pod = &ref{
+ Name: pod.Name,
+ UID: string(pod.UID),
+ }
+ case secret != nil:
+ pc.Kubernetes.Secret = &ref{
+ Name: secret.Name,
+ UID: string(secret.UID),
+ }
+ }
+ return sc, pc
+}
+
+func NewValidator(audiences []string, getter ServiceAccountTokenGetter) Validator {
+ return &validator{
+ auds: audiences,
+ getter: getter,
+ }
+}
+
+type validator struct {
+ auds []string
+ getter ServiceAccountTokenGetter
+}
+
+var _ = Validator(&validator{})
+
+func (v *validator) Validate(_ string, public *jwt.Claims, privateObj interface{}) (string, string, string, error) {
+ private, ok := privateObj.(*privateClaims)
+ if !ok {
+ glog.Errorf("jwt validator expected private claim of type *privateClaims but got: %T", privateObj)
+ return "", "", "", errors.New("Token could not be validated.")
+ }
+ err := public.Validate(jwt.Expected{
+ Time: now(),
+ })
+ switch {
+ case err == nil:
+ case err == jwt.ErrExpired:
+ return "", "", "", errors.New("Token has expired.")
+ default:
+ glog.Errorf("unexpected validation error: %T", err)
+ return "", "", "", errors.New("Token could not be validated.")
+ }
+
+ var audValid bool
+
+ for _, aud := range v.auds {
+ audValid = public.Audience.Contains(aud)
+ if audValid {
+ break
+ }
+ }
+
+ if !audValid {
+ return "", "", "", errors.New("Token is invalid for this audience.")
+ }
+
+ namespace := private.Kubernetes.Namespace
+ saref := private.Kubernetes.Svcacct
+ podref := private.Kubernetes.Pod
+ secref := private.Kubernetes.Secret
+ // Make sure service account still exists (name and UID)
+ serviceAccount, err := v.getter.GetServiceAccount(namespace, saref.Name)
+ if err != nil {
+ glog.V(4).Infof("Could not retrieve service account %s/%s: %v", namespace, saref.Name, err)
+ return "", "", "", err
+ }
+ if serviceAccount.DeletionTimestamp != nil {
+ glog.V(4).Infof("Service account has been deleted %s/%s", namespace, saref.Name)
+ return "", "", "", fmt.Errorf("ServiceAccount %s/%s has been deleted", namespace, saref.Name)
+ }
+ if string(serviceAccount.UID) != saref.UID {
+ glog.V(4).Infof("Service account UID no longer matches %s/%s: %q != %q", namespace, saref.Name, string(serviceAccount.UID), saref.UID)
+ return "", "", "", fmt.Errorf("ServiceAccount UID (%s) does not match claim (%s)", serviceAccount.UID, saref.UID)
+ }
+
+ if secref != nil {
+ // Make sure token hasn't been invalidated by deletion of the secret
+ secret, err := v.getter.GetSecret(namespace, secref.Name)
+ if err != nil {
+ glog.V(4).Infof("Could not retrieve bound secret %s/%s for service account %s/%s: %v", namespace, secref.Name, namespace, saref.Name, err)
+ return "", "", "", errors.New("Token has been invalidated")
+ }
+ if secret.DeletionTimestamp != nil {
+ glog.V(4).Infof("Bound secret is deleted and awaiting removal: %s/%s for service account %s/%s", namespace, secref.Name, namespace, saref.Name)
+ return "", "", "", errors.New("Token has been invalidated")
+ }
+ if string(secref.UID) != secref.UID {
+ glog.V(4).Infof("Secret UID no longer matches %s/%s: %q != %q", namespace, secref.Name, string(serviceAccount.UID), secref.UID)
+ return "", "", "", fmt.Errorf("Secret UID (%s) does not match claim (%s)", secret.UID, secref.UID)
+ }
+ }
+
+ if podref != nil {
+ // Make sure token hasn't been invalidated by deletion of the pod
+ pod, err := v.getter.GetPod(namespace, podref.Name)
+ if err != nil {
+ glog.V(4).Infof("Could not retrieve bound secret %s/%s for service account %s/%s: %v", namespace, podref.Name, namespace, saref.Name, err)
+ return "", "", "", errors.New("Token has been invalidated")
+ }
+ if pod.DeletionTimestamp != nil {
+ glog.V(4).Infof("Bound pod is deleted and awaiting removal: %s/%s for service account %s/%s", namespace, podref.Name, namespace, saref.Name)
+ return "", "", "", errors.New("Token has been invalidated")
+ }
+ if string(podref.UID) != podref.UID {
+ glog.V(4).Infof("Pod UID no longer matches %s/%s: %q != %q", namespace, podref.Name, string(serviceAccount.UID), podref.UID)
+ return "", "", "", fmt.Errorf("Pod UID (%s) does not match claim (%s)", pod.UID, podref.UID)
+ }
+ }
+
+ return private.Kubernetes.Namespace, private.Kubernetes.Svcacct.Name, private.Kubernetes.Svcacct.UID, nil
+}
+
+func (v *validator) NewPrivateClaims() interface{} {
+ return &privateClaims{}
+}