Skip to content

Commit

Permalink
Invalidate and remove join tokens after use (#207)
Browse files Browse the repository at this point in the history
* Invalidate and remove join tokens after worker install is finished

* Use "token invalidate", skip when "--no-wait"

* Needs sudo

* Add trace logging

* Prototype token decoding

* More prototyping

* Fancy token decoder

* Wrong pkg

* Lint

* There was a test also that was forgotten to add
  • Loading branch information
kke committed Oct 11, 2021
1 parent 2101848 commit 51869b1
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
53 changes: 53 additions & 0 deletions config/cluster/k0s.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package cluster

import (
"compress/gzip"
"encoding/base64"
"fmt"
"io"
"strings"
"time"

Expand All @@ -10,6 +14,7 @@ import (
"github.com/k0sproject/k0sctl/integration/github"
"github.com/k0sproject/k0sctl/version"
"github.com/k0sproject/rig/exec"
"gopkg.in/yaml.v2"
)

// K0sMinVersion is the minimum k0s version supported
Expand Down Expand Up @@ -77,3 +82,51 @@ func (k K0s) GenerateToken(h *Host, role string, expiry time.Duration) (token st
func (k K0s) GetClusterID(h *Host) (string, error) {
return h.ExecOutput(h.Configurer.KubectlCmdf("get -n kube-system namespace kube-system -o template={{.metadata.uid}}"), exec.Sudo(h))
}

// TokenID returns a token id from a token string that can be used to invalidate the token
func TokenID(s string) (string, error) {
b64 := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
_, err := base64.StdEncoding.Decode(b64, []byte(s))
if err != nil {
return "", fmt.Errorf("failed to decode token: %w", err)
}

sr := strings.NewReader(s)
b64r := base64.NewDecoder(base64.StdEncoding, sr)
gzr, err := gzip.NewReader(b64r)
if err != nil {
return "", fmt.Errorf("failed to create a reader for token: %w", err)
}
defer gzr.Close()

c, err := io.ReadAll(gzr)
if err != nil {
return "", fmt.Errorf("failed to uncompress token: %w", err)
}
cfg := dig.Mapping{}
err = yaml.Unmarshal(c, &cfg)
if err != nil {
return "", fmt.Errorf("failed to unmarshal token: %w", err)
}

users, ok := cfg.Dig("users").([]interface{})
if !ok || len(users) < 1 {
return "", fmt.Errorf("failed to find users in token")
}

user, ok := users[0].(dig.Mapping)
if !ok {
return "", fmt.Errorf("failed to find user in token")
}

token, ok := user.Dig("user", "token").(string)
if !ok {
return "", fmt.Errorf("failed to find user token in token")
}

idx := strings.IndexRune(token, '.')
if idx < 0 {
return "", fmt.Errorf("failed to find separator in token")
}
return token[0:idx], nil
}
15 changes: 15 additions & 0 deletions config/cluster/k0s_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cluster

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestTokenID(t *testing.T) {
token := "H4sIAAAAAAAC/2xVXY/iOBZ9r1/BH6geO4GeAWkfKiEmGGLKjn1N/BbidAFOgjuk+Frtf18V3SPtSvN2fc/ROdaVfc9L6Q9Q9+fDqZuNLvilaj7PQ92fZy+vo9/17GU0Go3OdX+p+9loPwz+PPvjD/xn8A3/+Q19C2bfx+Pwyanqfjj8OFTlUL+Wn8P+1B+G+6sth3I2WudoWOc4FspSeYjmAqjKlaEcESWeGBpih2muRCQSNucavEEkzBWNDGoApDV1t19W6uNSbJsyRzS1mPc7TVdiDknV0qNFQmjl1zvsaZmao3RECHVd8YZEFtlEgGW8ISmXBIQiY6km+wwbr5v9yoIvVHs71pL81CAio0yYpQ2DJMFSe1InWHEZMZHQveiqa/3hf2Eg+v/FpKJdnZifHCA2aKK5IwwSsbVzYnZgJkWLdUZ8IbfCZA5CE1hSKhxliZ2rkKRxw2hxZIlSEHMgwFWCckUTi8iTmyNy+ZqJUtktO2Y9C8Wpuk8DsTUT7ehnjt9uBTQ0T7yDB9nyw+A4Tlb5wt2NbHgB5LSJpwvR2Ytpp6oKm/lG2ZvUZoDERjs9vubzamxJcZEaX6vDwLKWFeUWIoOqi7z/hWx7c2q77DfcJ5BkQQFAyxYw6xix8BZILAar8Ha3GM7l420ssZ/UZE/rrQtUytSus4ssXGKOissKkdgiOskw1fowPKRqxnFLPy0hj1pPvV6IC0t4AOhGgZDlZjFdGYdXLBVZBozKrUccW6Ra2mQNm5sF9bsHXRVqv8lB7E3XmNyZjKHTSm7Jp82HyxoJDom56HY8zgFa6/xCoOtdIL8qF8t71rDUYBZAI247ZHnpiluZn+9WNu8GsvEusFuOpvNS20J/+GUN1aN2U2kfpFQouVaBj3PsW6VgXwXVeJfSd4DlLdN2JR+gqoAed8hEBcB7OXc4J3Dl2jLuSCQCL0pHo9jhiCU2ygCcSC3hh2moFEQWNTFvfaQS2snGLJXDMdfFWCiquBKRUh8XqZZXgZIbaJEYTLbcUQnBtLDkY8VbWuzmMAhH97ka1tWWKN1lvQFLICEb3tq+0vu+VNXEPqKvN/gQjkQSsejLv3BsUjTRNk8mpNbMF46d1Ju/SURPRWihBOJtS5eVwp9ZQhvIB8+UCo1ksSXg7IPcS2wNc35cphHKVKNE4rebbSR2ODpxd5uYAA/VfH+JW9Jt1GRv231eJ9mj1uao2+Z7pRrB2ulP4+xF5kOxDtUF3PLKJXmXCb4XgQmzuRFVmmGZnCaA/nrIBdCvuRduvMpVs8lcNi7UcDVhRG0A93JLYpP66yqYgJoLoZumlQ9x2xFD8znIkux77oacdWqSdZSVyjCWnkKmb+9WDz/Nh5+b9O1SIDIUHaC6bW5V4qFsYSnSRmUIloXCuV1MaE7IsQAxBkR5ndqASRZtFDVGm7VszHGzwEfhJqzUzTV2tMi1iG369dfsmjVvkxKKfhMPgjsccEUPLMmCTcJCsTDrfGHGdXsOJcBpo4ezQd7sQroC3EQrdLtVD+Z16lZCY58rEO8SrX7vZiId/+AIckiaRa5YBIl67uU1P/3rZTTqyraejRw6v1Snbqhvw6+U+FX/Som/I+PJ+mp8np+nz13d1MPr7nQazkNf+v9X++z7uhte/1Z6Nt2hs7NRfOp+HD5efF//qPu6q+rzbPTv/7x8qT7Nf4v8g/zT+HmF4eTqbjY6fD+E949vVzeZ7vHx8mM6uPCATi//DQAA//+MVAsnAgcAAA=="

id, err := TokenID(token)
require.NoError(t, err)
require.Equal(t, "i6i3yg", id)
}
17 changes: 17 additions & 0 deletions phase/install_controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/k0sproject/k0sctl/config"
"github.com/k0sproject/k0sctl/config/cluster"
"github.com/k0sproject/rig/exec"
log "github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -60,12 +61,28 @@ func (p *InstallControllers) Run() error {
if err != nil {
return err
}
tokenID, err := cluster.TokenID(token)
if err != nil {
return err
}
log.Debugf("%s: join token ID: %s", p.leader, tokenID)
defer func() {
if err := p.leader.Exec(p.leader.Configurer.K0sCmdf("token invalidate %s", tokenID), exec.Sudo(p.leader), exec.RedactString(token)); err != nil {
log.Warnf("%s: failed to invalidate the controller join token", p.leader)
}
}()

log.Infof("%s: writing join token", h)
if err := h.Configurer.WriteFile(h, h.K0sJoinTokenPath(), token, "0640"); err != nil {
return err
}

defer func() {
if err := h.Configurer.DeleteFile(h, h.K0sJoinTokenPath()); err != nil {
log.Warnf("%s: failed to clean up the join token file at %s", h, h.K0sJoinTokenPath())
}
}()

log.Infof("%s: installing k0s controller", h)
if err := h.Exec(h.K0sInstallCommand()); err != nil {
return err
Expand Down
23 changes: 23 additions & 0 deletions phase/install_workers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/k0sproject/k0sctl/config"
"github.com/k0sproject/k0sctl/config/cluster"
"github.com/k0sproject/rig/exec"
log "github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -76,12 +77,34 @@ func (p *InstallWorkers) Run() error {
return err
}

tokenID, err := cluster.TokenID(token)
if err != nil {
return err
}
log.Debugf("%s: join token ID: %s", p.leader, tokenID)

if !NoWait {
defer func() {
if err := p.leader.Exec(p.leader.Configurer.K0sCmdf("token invalidate %s", tokenID), exec.Sudo(p.leader), exec.RedactString(token)); err != nil {
log.Warnf("%s: failed to invalidate the worker join token", p.leader)
}
}()
}

return p.hosts.ParallelEach(func(h *cluster.Host) error {
log.Infof("%s: writing join token", h)
if err := h.Configurer.WriteFile(h, h.K0sJoinTokenPath(), token, "0640"); err != nil {
return err
}

if !NoWait {
defer func() {
if err := h.Configurer.DeleteFile(h, h.K0sJoinTokenPath()); err != nil {
log.Warnf("%s: failed to clean up the join token file at %s", h, h.K0sJoinTokenPath())
}
}()
}

if sp, err := h.Configurer.ServiceScriptPath(h, h.K0sServiceName()); err == nil {
if h.Configurer.ServiceIsRunning(h, h.K0sServiceName()) {
log.Infof("%s: stopping service", h)
Expand Down

0 comments on commit 51869b1

Please sign in to comment.