Add ServiceAccountToken SecretType

pull/6/head
Jordan Liggitt 2015-04-27 23:51:20 -04:00
parent 86800eafa7
commit 6e1e7dbb24
9 changed files with 163 additions and 5 deletions

View File

@ -284,6 +284,7 @@ _kubectl_describe()
must_have_one_noun+=("pod")
must_have_one_noun+=("replicationcontroller")
must_have_one_noun+=("resourcequota")
must_have_one_noun+=("secret")
must_have_one_noun+=("service")
}

View File

@ -1802,7 +1802,23 @@ const MaxSecretSize = 1 * 1024 * 1024
type SecretType string
const (
SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data
// SecretTypeOpaque is the default; arbitrary user-defined data
SecretTypeOpaque SecretType = "Opaque"
// SecretTypeServiceAccountToken contains a token that identifies a service account to the API
//
// Required fields:
// - Secret.Annotations["kubernetes.io/service-account.name"] - the name of the ServiceAccount the token identifies
// - Secret.Annotations["kubernetes.io/service-account.uid"] - the UID of the ServiceAccount the token identifies
// - Secret.Data["token"] - a token that identifies the service account to the API
SecretTypeServiceAccountToken SecretType = "kubernetes.io/service-account-token"
// ServiceAccountNameKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountNameKey = "kubernetes.io/service-account.name"
// ServiceAccountUIDKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
ServiceAccountTokenKey = "token"
)
type SecretList struct {

View File

@ -1705,7 +1705,23 @@ const MaxSecretSize = 1 * 1024 * 1024
type SecretType string
const (
SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data
// SecretTypeOpaque is the default; arbitrary user-defined data
SecretTypeOpaque SecretType = "Opaque"
// SecretTypeServiceAccountToken contains a token that identifies a service account to the API
//
// Required fields:
// - Secret.Annotations["kubernetes.io/service-account.name"] - the name of the ServiceAccount the token identifies
// - Secret.Annotations["kubernetes.io/service-account.uid"] - the UID of the ServiceAccount the token identifies
// - Secret.Data["token"] - a token that identifies the service account to the API
SecretTypeServiceAccountToken SecretType = "kubernetes.io/service-account-token"
// ServiceAccountNameKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountNameKey = "kubernetes.io/service-account.name"
// ServiceAccountUIDKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
ServiceAccountTokenKey = "token"
)
type SecretList struct {

View File

@ -1614,7 +1614,23 @@ const MaxSecretSize = 1 * 1024 * 1024
type SecretType string
const (
SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data
// SecretTypeOpaque is the default; arbitrary user-defined data
SecretTypeOpaque SecretType = "Opaque"
// SecretTypeServiceAccountToken contains a token that identifies a service account to the API
//
// Required fields:
// - Secret.Annotations["kubernetes.io/service-account.name"] - the name of the ServiceAccount the token identifies
// - Secret.Annotations["kubernetes.io/service-account.uid"] - the UID of the ServiceAccount the token identifies
// - Secret.Data["token"] - a token that identifies the service account to the API
SecretTypeServiceAccountToken SecretType = "kubernetes.io/service-account-token"
// ServiceAccountNameKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountNameKey = "kubernetes.io/service-account.name"
// ServiceAccountUIDKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
ServiceAccountTokenKey = "token"
)
type SecretList struct {

View File

@ -1689,7 +1689,23 @@ const MaxSecretSize = 1 * 1024 * 1024
type SecretType string
const (
SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data
// SecretTypeOpaque is the default; arbitrary user-defined data
SecretTypeOpaque SecretType = "Opaque"
// SecretTypeServiceAccountToken contains a token that identifies a service account to the API
//
// Required fields:
// - Secret.Annotations["kubernetes.io/service-account.name"] - the name of the ServiceAccount the token identifies
// - Secret.Annotations["kubernetes.io/service-account.uid"] - the UID of the ServiceAccount the token identifies
// - Secret.Data["token"] - a token that identifies the service account to the API
SecretTypeServiceAccountToken SecretType = "kubernetes.io/service-account-token"
// ServiceAccountNameKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountNameKey = "kubernetes.io/service-account.name"
// ServiceAccountUIDKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
ServiceAccountTokenKey = "token"
)
type SecretList struct {

View File

@ -1705,7 +1705,23 @@ const MaxSecretSize = 1 * 1024 * 1024
type SecretType string
const (
SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data
// SecretTypeOpaque is the default; arbitrary user-defined data
SecretTypeOpaque SecretType = "Opaque"
// SecretTypeServiceAccountToken contains a token that identifies a service account to the API
//
// Required fields:
// - Secret.Annotations["kubernetes.io/service-account.name"] - the name of the ServiceAccount the token identifies
// - Secret.Annotations["kubernetes.io/service-account.uid"] - the UID of the ServiceAccount the token identifies
// - Secret.Data["token"] - a token that identifies the service account to the API
SecretTypeServiceAccountToken SecretType = "kubernetes.io/service-account-token"
// ServiceAccountNameKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountNameKey = "kubernetes.io/service-account.name"
// ServiceAccountUIDKey is the key of the required annotation for SecretTypeServiceAccountToken secrets
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
ServiceAccountTokenKey = "token"
)
type SecretList struct {

View File

@ -1244,6 +1244,12 @@ func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
}
switch secret.Type {
case api.SecretTypeServiceAccountToken:
// Only require Annotations[kubernetes.io/service-account.name]
// Additional fields (like Annotations[kubernetes.io/service-account.uid] and Data[token]) might be contributed later by a controller loop
if value := secret.Annotations[api.ServiceAccountNameKey]; len(value) == 0 {
allErrs = append(allErrs, errs.NewFieldRequired(fmt.Sprintf("metadata.annotations[%s]", api.ServiceAccountNameKey)))
}
case api.SecretTypeOpaque, "":
// no-op
default:

View File

@ -2961,6 +2961,7 @@ func TestValidateNamespaceUpdate(t *testing.T) {
}
func TestValidateSecret(t *testing.T) {
// Opaque secret validation
validSecret := func() api.Secret {
return api.Secret{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
@ -2988,6 +2989,32 @@ func TestValidateSecret(t *testing.T) {
}
invalidKey.Data["a..b"] = []byte("whoops")
// kubernetes.io/service-account-token secret validation
validServiceAccountTokenSecret := func() api.Secret {
return api.Secret{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "bar",
Annotations: map[string]string{
api.ServiceAccountNameKey: "foo",
},
},
Type: api.SecretTypeServiceAccountToken,
Data: map[string][]byte{
"data-1": []byte("bar"),
},
}
}
var (
emptyTokenAnnotation = validServiceAccountTokenSecret()
missingTokenAnnotation = validServiceAccountTokenSecret()
missingTokenAnnotations = validServiceAccountTokenSecret()
)
emptyTokenAnnotation.Annotations[api.ServiceAccountNameKey] = ""
delete(missingTokenAnnotation.Annotations, api.ServiceAccountNameKey)
missingTokenAnnotations.Annotations = nil
tests := map[string]struct {
secret api.Secret
valid bool
@ -2999,6 +3026,11 @@ func TestValidateSecret(t *testing.T) {
"invalid namespace": {invalidNs, false},
"over max size": {overMaxSize, false},
"invalid key": {invalidKey, false},
"valid service-account-token secret": {validServiceAccountTokenSecret(), true},
"empty service-account-token annotation": {emptyTokenAnnotation, false},
"missing service-account-token annotation": {missingTokenAnnotation, false},
"missing service-account-token annotations": {missingTokenAnnotations, false},
}
for name, tc := range tests {

View File

@ -64,6 +64,7 @@ func describerMap(c *client.Client) map[string]Describer {
m := map[string]Describer{
"Pod": &PodDescriber{c},
"ReplicationController": &ReplicationControllerDescriber{c},
"Secret": &SecretDescriber{c},
"Service": &ServiceDescriber{c},
"Minion": &NodeDescriber{c},
"Node": &NodeDescriber{c},
@ -421,6 +422,44 @@ func describeReplicationController(controller *api.ReplicationController, events
})
}
// SecretDescriber generates information about a secret
type SecretDescriber struct {
client.Interface
}
func (d *SecretDescriber) Describe(namespace, name string) (string, error) {
c := d.Secrets(namespace)
secret, err := c.Get(name)
if err != nil {
return "", err
}
return describeSecret(secret)
}
func describeSecret(secret *api.Secret) (string, error) {
return tabbedString(func(out io.Writer) error {
fmt.Fprintf(out, "Name:\t%s\n", secret.Name)
fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(secret.Labels))
fmt.Fprintf(out, "Annotations:\t%s\n", formatLabels(secret.Annotations))
fmt.Fprintf(out, "\nType:\t%s\n", secret.Type)
fmt.Fprintf(out, "\nData\n====\n")
for k, v := range secret.Data {
switch {
case k == api.ServiceAccountTokenKey && secret.Type == api.SecretTypeServiceAccountToken:
fmt.Fprintf(out, "%s:\t%s\n", k, string(v))
default:
fmt.Fprintf(out, "%s:\t%d bytes\n", k, len(v))
}
}
return nil
})
}
// ServiceDescriber generates information about a service.
type ServiceDescriber struct {
client.Interface