Skip to content

Commit

Permalink
Remove kubeconfig API endpoint
Browse files Browse the repository at this point in the history
Since the refactoring to use Calico host containers on Windows, there's
no need for this endpoint anymore. Remove it along with its associated
bootstrap token usage. Also, replace the API authorization based on the
k0s "role" with an authorization based directly on the bootstrap token
usages, since only the "controller" role was left.

See: bb7b580 ("Helper to get correct node name for windows")
Signed-off-by: Tom Wieczorek <[email protected]>
  • Loading branch information
twz123 committed Feb 6, 2024
1 parent 3a518d8 commit b4daf7e
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 97 deletions.
100 changes: 6 additions & 94 deletions cmd/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ package api
import (
"context"
"crypto/tls"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
Expand All @@ -32,14 +30,12 @@ import (

k0slog "github.com/k0sproject/k0s/internal/pkg/log"
mw "github.com/k0sproject/k0s/internal/pkg/middleware"
"github.com/k0sproject/k0s/internal/pkg/templatewriter"
"github.com/k0sproject/k0s/pkg/apis/k0s/v1beta1"
"github.com/k0sproject/k0s/pkg/config"
"github.com/k0sproject/k0s/pkg/constant"
"github.com/k0sproject/k0s/pkg/etcd"
kubeutil "github.com/k0sproject/k0s/pkg/kubernetes"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"

Expand All @@ -52,16 +48,6 @@ type command struct {
client kubernetes.Interface
}

const (
workerRole = "worker"
controllerRole = "controller"
)

var allowedUsageByRole = map[string]string{
workerRole: "usage-bootstrap-api-worker-calls",
controllerRole: "usage-controller-join",
}

func NewAPICmd() *cobra.Command {
cmd := &cobra.Command{
Use: "api",
Expand Down Expand Up @@ -102,16 +88,13 @@ func (c *command) start() (err error) {
// Only mount the etcd handler if we're running on internal etcd storage
// by default the mux will return 404 back which the caller should handle
mux.Handle(prefix+"/etcd/members", mw.AllowMethods(http.MethodPost)(
c.controllerHandler(c.etcdHandler())))
c.authMiddleware(c.etcdHandler(), "usage-controller-join")))
}

if storage.IsJoinable() {
mux.Handle(prefix+"/ca", mw.AllowMethods(http.MethodGet)(
c.controllerHandler(c.caHandler())))
c.authMiddleware(c.caHandler(), "usage-controller-join")))
}
mux.Handle(prefix+"/calico/kubeconfig", mw.AllowMethods(http.MethodGet)(
c.workerHandler(c.kubeConfigHandler(nodeConfig.Spec.API.APIAddressURL())),
))

srv := &http.Server{
Handler: mux,
Expand Down Expand Up @@ -186,69 +169,6 @@ func (c *command) etcdHandler() http.Handler {
})
}

func (c *command) kubeConfigHandler(apiAddress string) http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
tpl := `apiVersion: v1
kind: Config
clusters:
- name: kubernetes
cluster:
certificate-authority-data: {{ .Ca }}
server: {{ .Server }}
contexts:
- name: calico-windows@kubernetes
context:
cluster: kubernetes
namespace: kube-system
user: calico-windows
current-context: calico-windows@kubernetes
users:
- name: calico-windows
user:
token: {{ .Token }}
`
l, err := c.client.CoreV1().Secrets("kube-system").List(context.Background(), metav1.ListOptions{})
if err != nil {
sendError(err, resp)
return
}
found := false
var secretWithToken corev1.Secret
for _, secret := range l.Items {
if !strings.HasPrefix(secret.Name, "calico-node-token") {
continue
}
found = true
secretWithToken = secret
break
}
if !found {
sendError(errors.New("no calico-node-token secret found"), resp)
return
}

tw := templatewriter.TemplateWriter{
Name: "kube-config",
Template: tpl,
Data: struct {
Server string
Ca string
Token string
Namespace string
}{
Server: apiAddress,
Ca: base64.StdEncoding.EncodeToString(secretWithToken.Data["ca.crt"]),
Token: string(secretWithToken.Data["token"]),
Namespace: string(secretWithToken.Data["namespace"]),
},
}
if err := tw.WriteToBuffer(resp); err != nil {
sendError(err, resp)
return
}
})
}

func (c *command) caHandler() http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
caResp := v1beta1.CaResponse{}
Expand Down Expand Up @@ -294,7 +214,7 @@ func (c *command) caHandler() http.Handler {
// We need to validate:
// - that we find a secret with the ID
// - that the token matches whats inside the secret
func (c *command) isValidToken(ctx context.Context, token string, role string) bool {
func (c *command) isValidToken(ctx context.Context, token string, usage string) bool {
parts := strings.Split(token, ".")
logrus.Debugf("token parts: %v", parts)
if len(parts) != 2 {
Expand All @@ -312,15 +232,15 @@ func (c *command) isValidToken(ctx context.Context, token string, role string) b
return false
}

usageValue, ok := secret.Data[allowedUsageByRole[role]]
usageValue, ok := secret.Data[usage]
if !ok || string(usageValue) != "true" {
return false
}

return true
}

func (c *command) authMiddleware(next http.Handler, role string) http.Handler {
func (c *command) authMiddleware(next http.Handler, usage string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
if auth == "" {
Expand All @@ -331,7 +251,7 @@ func (c *command) authMiddleware(next http.Handler, role string) http.Handler {
parts := strings.Split(auth, "Bearer ")
if len(parts) == 2 {
token := parts[1]
if !c.isValidToken(r.Context(), token, role) {
if !c.isValidToken(r.Context(), token, usage) {
sendError(fmt.Errorf("go away"), w, http.StatusUnauthorized)
return
}
Expand All @@ -343,11 +263,3 @@ func (c *command) authMiddleware(next http.Handler, role string) http.Handler {
next.ServeHTTP(w, r)
})
}

func (c *command) controllerHandler(next http.Handler) http.Handler {
return c.authMiddleware(next, controllerRole)
}

func (c *command) workerHandler(next http.Handler) http.Handler {
return c.authMiddleware(next, workerRole)
}
3 changes: 0 additions & 3 deletions pkg/token/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,8 @@ func RandomBootstrapSecret(role string, valid time.Duration) (*corev1.Secret, st
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)
Expand Down

0 comments on commit b4daf7e

Please sign in to comment.