Skip to content

Commit

Permalink
Merge pull request #4025 from twz123/preshared
Browse files Browse the repository at this point in the history
Refactor pre-shared token creation
  • Loading branch information
twz123 authored Feb 5, 2024
2 parents bfe2803 + c2c801c commit 3a518d8
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 71 deletions.
58 changes: 20 additions & 38 deletions cmd/token/preshared.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,23 @@ limitations under the License.
package token

import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"os"
"path/filepath"
"time"

"github.com/spf13/cobra"
v1 "k8s.io/api/core/v1"
fakeclientset "k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/testing"
"sigs.k8s.io/yaml"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/client-go/kubernetes/scheme"

"github.com/k0sproject/k0s/internal/pkg/file"
"github.com/k0sproject/k0s/pkg/config"
"github.com/k0sproject/k0s/pkg/token"

"github.com/spf13/cobra"
)

func preSharedCmd() *cobra.Command {
Expand Down Expand Up @@ -85,43 +86,24 @@ func preSharedCmd() *cobra.Command {
}

func createSecret(role string, validity time.Duration, outDir string) (string, error) {
fakeClient := fakeclientset.NewSimpleClientset()

manager, err := token.NewManagerForClient(fakeClient)
if err != nil {
return "", fmt.Errorf("error creating token manager: %w", err)
}

t, err := manager.Create(context.Background(), validity, role)
secret, token, err := token.RandomBootstrapSecret(role, validity)
if err != nil {
return "", fmt.Errorf("error creating token: %w", err)
return "", fmt.Errorf("failed to generate bootstrap secret: %w", err)
}

// Get created Secret from the fake client and write it as a file
for _, action := range fakeClient.Actions() {
a, ok := action.(testing.CreateActionImpl)
if !ok {
continue
}

secret, ok := a.GetObject().(*v1.Secret)
if !ok {
continue
}
secret.APIVersion = "v1"
secret.Kind = "Secret"

b, err := yaml.Marshal(secret)
if err != nil {
return "", fmt.Errorf("error marshailling secret: %w", err)
}

err = file.WriteContentAtomically(filepath.Join(outDir, secret.Name+".yaml"), b, 0640)
if err != nil {
return "", fmt.Errorf("error writing secret: %w", err)
if err := file.WriteAtomically(filepath.Join(outDir, secret.Name+".yaml"), 0640, func(unbuffered io.Writer) error {
serializer := json.NewYAMLSerializer(json.DefaultMetaFactory, scheme.Scheme, scheme.Scheme)
encoder := scheme.Codecs.EncoderForVersion(serializer, corev1.SchemeGroupVersion)
w := bufio.NewWriter(unbuffered)
if err := encoder.Encode(secret, w); err != nil {
return err
}
return w.Flush()
}); err != nil {
return "", fmt.Errorf("failed to save bootstrap secret: %w", err)
}
return t, nil

return token, nil
}

func createKubeConfig(tokenString, role, joinURL, certPath, outDir string) error {
Expand Down
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 3a518d8

Please sign in to comment.