Skip to content

Commit

Permalink
Extract BootstrapToken secret generation in its own function
Browse files Browse the repository at this point in the history
This allows the secret to be created without creating it in the cluster.

Signed-off-by: Tom Wieczorek <[email protected]>
  • Loading branch information
twz123 committed Feb 5, 2024
1 parent 4eabd5c commit c28d96e
Showing 1 changed file with 45 additions and 33 deletions.
78 changes: 45 additions & 33 deletions pkg/token/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ import (
"time"

"github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/client-go/kubernetes"

"github.com/k0sproject/k0s/internal/pkg/random"
Expand Down Expand Up @@ -65,48 +66,59 @@ type Manager struct {
client kubernetes.Interface
}

// Create creates a new bootstrap token
func (m *Manager) Create(ctx context.Context, valid time.Duration, role string) (string, error) {
func RandomBootstrapSecret(role string, valid time.Duration) (*corev1.Secret, string, error) {
tokenID := random.String(6)
tokenSecret := random.String(16)

token := fmt.Sprintf("%s.%s", tokenID, tokenSecret)
s := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("bootstrap-token-%s", tokenID),
Namespace: "kube-system",
},
Type: corev1.SecretTypeBootstrapToken,
StringData: map[string]string{
"token-id": tokenID,
"token-secret": tokenSecret,

// This "usage-" is shared for all roles of the token which allows
// them to execute calls to the k0s API. This is done because we
// need to call the k0s API from windows workers during the join
// step.
"usage-bootstrap-api-auth": "true",
},
}

data := make(map[string]string)
data["token-id"] = tokenID
data["token-secret"] = tokenSecret
if valid != 0 {
data["expiration"] = time.Now().Add(valid).UTC().Format(time.RFC3339)
logrus.Debugf("Set expiry to %s", data["expiration"])
exp := time.Now().Add(valid).UTC().Format(time.RFC3339)
s.StringData["expiration"] = exp
logrus.Debug("Set expiry to ", exp)
}

// This "usage-" is shared for both roles of the token
// which allows both roles execute calls to the k0s api.
// this is done because we need to call k0s api from
// windows workers during the join step
data["usage-bootstrap-api-auth"] = "true"

if role == "worker" {
data["description"] = "Worker bootstrap token generated by k0s"
data["usage-bootstrap-authentication"] = "true"
data["usage-bootstrap-api-worker-calls"] = "true"
} else {
data["description"] = "Controller bootstrap token generated by k0s"
data["usage-bootstrap-authentication"] = "false"
data["usage-bootstrap-signing"] = "false"
data["usage-controller-join"] = "true"
switch role {
case "worker":
s.StringData["description"] = "Worker bootstrap token generated by k0s"
s.StringData["usage-bootstrap-authentication"] = "true"
s.StringData["usage-bootstrap-api-worker-calls"] = "true"
case "controller":
s.StringData["description"] = "Controller bootstrap token generated by k0s"
s.StringData["usage-bootstrap-authentication"] = "false"
s.StringData["usage-bootstrap-signing"] = "false"
s.StringData["usage-controller-join"] = "true"
default:
return nil, "", fmt.Errorf("unsupported role %q", role)
}

secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("bootstrap-token-%s", tokenID),
Namespace: "kube-system",
},
Type: v1.SecretTypeBootstrapToken,
StringData: data,
return &s, fmt.Sprintf("%s.%s", tokenID, tokenSecret), nil
}

// Create creates a new bootstrap token
func (m *Manager) Create(ctx context.Context, valid time.Duration, role string) (string, error) {
secret, token, err := RandomBootstrapSecret(role, valid)
if err != nil {
return "", err
}

_, err := m.client.CoreV1().Secrets("kube-system").Create(ctx, secret, metav1.CreateOptions{})
_, err = m.client.CoreV1().Secrets("kube-system").Create(ctx, secret, metav1.CreateOptions{})
if err != nil {
return "", err
}
Expand All @@ -117,7 +129,7 @@ func (m *Manager) Create(ctx context.Context, valid time.Duration, role string)
// List returns all the join tokens for given role. If role == "" then it returns all join tokens
func (m *Manager) List(ctx context.Context, role string) ([]Token, error) {
tokenList, err := m.client.CoreV1().Secrets("kube-system").List(ctx, metav1.ListOptions{
FieldSelector: "type=bootstrap.kubernetes.io/token",
FieldSelector: fields.OneTermEqualSelector("type", string(corev1.SecretTypeBootstrapToken)).String(),
})
if err != nil {
return nil, err
Expand Down

0 comments on commit c28d96e

Please sign in to comment.