refactor bootstrap token utils

This commit is contained in:
Di Xu
2019-04-29 20:52:48 +08:00
parent 00e13dbc12
commit af9ae4c11a
11 changed files with 352 additions and 296 deletions

View File

@@ -31,6 +31,7 @@ import (
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
bootstrapsecretutil "k8s.io/cluster-bootstrap/util/secrets"
"k8s.io/klog"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/controller"
@@ -187,7 +188,7 @@ func (tc *TokenCleaner) syncFunc(key string) error {
func (tc *TokenCleaner) evalSecret(o interface{}) {
secret := o.(*v1.Secret)
if isSecretExpired(secret) {
if bootstrapsecretutil.HasExpired(secret, time.Now()) {
klog.V(3).Infof("Deleting expired secret %s/%s", secret.Namespace, secret.Name)
var options *metav1.DeleteOptions
if len(secret.UID) > 0 {

View File

@@ -17,46 +17,23 @@ limitations under the License.
package bootstrap
import (
"regexp"
"time"
"k8s.io/klog"
"k8s.io/api/core/v1"
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
bootstrapsecretutil "k8s.io/cluster-bootstrap/util/secrets"
)
var namePattern = `^` + regexp.QuoteMeta(bootstrapapi.BootstrapTokenSecretPrefix) + `([a-z0-9]{6})$`
var nameRegExp = regexp.MustCompile(namePattern)
// getSecretString gets a string value from a secret. If there is an error or
// if the key doesn't exist, an empty string is returned.
func getSecretString(secret *v1.Secret, key string) string {
data, ok := secret.Data[key]
if !ok {
return ""
}
return string(data)
}
// parseSecretName parses the name of the secret to extract the secret ID.
func parseSecretName(name string) (secretID string, ok bool) {
r := nameRegExp.FindStringSubmatch(name)
if r == nil {
return "", false
}
return r[1], true
}
func validateSecretForSigning(secret *v1.Secret) (tokenID, tokenSecret string, ok bool) {
nameTokenID, ok := parseSecretName(secret.Name)
nameTokenID, ok := bootstrapsecretutil.ParseName(secret.Name)
if !ok {
klog.V(3).Infof("Invalid secret name: %s. Must be of form %s<secret-id>.", secret.Name, bootstrapapi.BootstrapTokenSecretPrefix)
return "", "", false
}
tokenID = getSecretString(secret, bootstrapapi.BootstrapTokenIDKey)
tokenID = bootstrapsecretutil.GetData(secret, bootstrapapi.BootstrapTokenIDKey)
if len(tokenID) == 0 {
klog.V(3).Infof("No %s key in %s/%s Secret", bootstrapapi.BootstrapTokenIDKey, secret.Namespace, secret.Name)
return "", "", false
@@ -67,7 +44,7 @@ func validateSecretForSigning(secret *v1.Secret) (tokenID, tokenSecret string, o
return "", "", false
}
tokenSecret = getSecretString(secret, bootstrapapi.BootstrapTokenSecretKey)
tokenSecret = bootstrapsecretutil.GetData(secret, bootstrapapi.BootstrapTokenSecretKey)
if len(tokenSecret) == 0 {
klog.V(3).Infof("No %s key in %s/%s Secret", bootstrapapi.BootstrapTokenSecretKey, secret.Namespace, secret.Name)
return "", "", false
@@ -76,34 +53,15 @@ func validateSecretForSigning(secret *v1.Secret) (tokenID, tokenSecret string, o
// Ensure this secret hasn't expired. The TokenCleaner should remove this
// but if that isn't working or it hasn't gotten there yet we should check
// here.
if isSecretExpired(secret) {
if bootstrapsecretutil.HasExpired(secret, time.Now()) {
return "", "", false
}
// Make sure this secret can be used for signing
okToSign := getSecretString(secret, bootstrapapi.BootstrapTokenUsageSigningKey)
okToSign := bootstrapsecretutil.GetData(secret, bootstrapapi.BootstrapTokenUsageSigningKey)
if okToSign != "true" {
return "", "", false
}
return tokenID, tokenSecret, true
}
// isSecretExpired returns true if the Secret is expired.
func isSecretExpired(secret *v1.Secret) bool {
expiration := getSecretString(secret, bootstrapapi.BootstrapTokenExpirationKey)
if len(expiration) > 0 {
expTime, err2 := time.Parse(time.RFC3339, expiration)
if err2 != nil {
klog.V(3).Infof("Unparseable expiration time (%s) in %s/%s Secret: %v. Treating as expired.",
expiration, secret.Namespace, secret.Name, err2)
return true
}
if time.Now().After(expTime) {
klog.V(3).Infof("Expired bootstrap token in %s/%s Secret: %v",
secret.Namespace, secret.Name, expiration)
return true
}
}
return false
}

View File

@@ -20,8 +20,6 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
@@ -180,27 +178,3 @@ func TestMismatchSecretName(t *testing.T) {
t.Errorf("Token validation should fail with mismatched name")
}
}
func TestParseSecretName(t *testing.T) {
tokenID, ok := parseSecretName("bootstrap-token-abc123")
assert.True(t, ok, "parseSecretName should accept valid name")
assert.Equal(t, "abc123", tokenID, "parseSecretName should return token ID")
_, ok = parseSecretName("")
assert.False(t, ok, "parseSecretName should reject blank name")
_, ok = parseSecretName("abc123")
assert.False(t, ok, "parseSecretName should reject with no prefix")
_, ok = parseSecretName("bootstrap-token-")
assert.False(t, ok, "parseSecretName should reject no token ID")
_, ok = parseSecretName("bootstrap-token-abc")
assert.False(t, ok, "parseSecretName should reject short token ID")
_, ok = parseSecretName("bootstrap-token-abc123ghi")
assert.False(t, ok, "parseSecretName should reject long token ID")
_, ok = parseSecretName("bootstrap-token-ABC123")
assert.False(t, ok, "parseSecretName should reject invalid token ID")
}