Skip to content
Permalink
Browse files
refresh kubernetes token
  • Loading branch information
bradrydzewski committed Oct 19, 2019
1 parent 309888e commit fd3ba39650f7b2adc976e4a61a71e6c559b9d055
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 50 deletions.
7 go.mod
@@ -8,16 +8,17 @@ require (
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
github.com/google/go-cmp v0.2.0
github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357
github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186
github.com/hashicorp/go-cleanhttp v0.5.1
github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6
github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90
github.com/hashicorp/go-rootcerts v1.0.0
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce
github.com/hashicorp/nomad/api v0.0.0-20191018195330-75acbccf8e5e
github.com/hashicorp/vault v0.10.4
github.com/joho/godotenv v1.2.0
github.com/kelseyhightower/envconfig v1.3.0
github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff
github.com/mitchellh/go-homedir v1.0.0
github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699
github.com/ryanuber/go-glob v0.0.0-20160226084822-572520ed46db
github.com/sirupsen/logrus v1.0.6
30 go.sum
@@ -1,39 +1,69 @@
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e h1:rl2Aq4ZODqTDkeSqQBy+fzpZPamacO1Srp8zq7jf2Sc=
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/drone/drone-go v0.0.0-20181022043707-2d78f279e8ef h1:uF5LIQ4au8WfPJ8FxFiyZBbie2Y1sg5QKKGWM3vgqnY=
github.com/drone/drone-go v0.0.0-20181022043707-2d78f279e8ef/go.mod h1:qVb1k1w9X5jgoGyLtbnfWNnd4XZfAwokxBmiutbpGqw=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 h1:f0n1xnMSmBLzVfsMMvriDyA75NB/oBgILX2GcHXIQzY=
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357 h1:Rem2+U35z1QtPQc6r+WolF7yXiefXqDKyk+lN2pE164=
github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186 h1:URgjUo+bs1KwatoNbwG0uCO4dHN4r1jsp4a5AGgHRjo=
github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0 h1:j30noezaCfvNLcdMYSvHLv81DxYRSt1grlpseG67vhU=
github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6 h1:qCv4319q2q7XKn0MQbi8p37hsJ+9Xo8e6yojA73JVxk=
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM=
github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90 h1:VBj0QYQ0u2MCJzBfeYXGexnAl17GsH1yidnoxCqqD9E=
github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90/go.mod h1:o4zcYY1e0GEZI6eSEr+43QDYmuGglw1qSO6qdHUHCgg=
github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 h1:7YOlAIO2YWnJZkQp7B5eFykaIY7C9JndqAFQyVV5BhM=
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno=
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/nomad/api v0.0.0-20191018195330-75acbccf8e5e h1:tN30pacDPf9eshNcOnV701mZGgNqDio67+a3wupgmwU=
github.com/hashicorp/nomad/api v0.0.0-20191018195330-75acbccf8e5e/go.mod h1:Kxg08r0mgxUeITzMRi/XGI6WcZiT8XY/5Ix1Q1G2jU0=
github.com/hashicorp/vault v0.10.4 h1:4x0lHxui/ZRp/B3E0Auv1QNBJpzETqHR2kQD3mHSBJU=
github.com/hashicorp/vault v0.10.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0=
github.com/joho/godotenv v1.2.0 h1:vGTvz69FzUFp+X4/bAkb0j5BoLC+9bpqTWY8mjhA9pc=
github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM=
github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff h1:jM4Eo4qMmmcqePS3u6X2lcEELtVuXWkWJIS/pRI3oSk=
github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699 h1:KXZJFdun9knAVAR8tg/aHJEr5DgtcbqyvzacK+CDCaI=
github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/ryanuber/go-glob v0.0.0-20160226084822-572520ed46db h1:ge9atzKq16843f793fDVxKUhmTb4H5muzjJQ6PgsnHg=
github.com/ryanuber/go-glob v0.0.0-20160226084822-572520ed46db/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20180808211826-de0752318171 h1:vYogbvSFj2YXcjQxFHu/rASSOt9sLytpCaSkiwQ135I=
golang.org/x/crypto v0.0.0-20180808211826-de0752318171/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180811021610-c39426892332 h1:efGso+ep0DjyCBJPjvoz0HI6UldX4Md2F1rZFe1ir0E=
42 main.go
@@ -74,34 +74,44 @@ func main() {
logrus.Fatalln(err)
}

// global context
ctx := context.Background()

http.Handle("/", secret.Handler(
spec.Secret,
plugin.New(client),
logrus.StandardLogger(),
))

var g errgroup.Group

// the token can be fetched at runtime if an auth
// provider is configured. otherwise, the user must
// specify a VAULT_TOKEN.
if spec.VaultAuthType == kubernetes.Name {
token, err := kubernetes.Load(
renewer := kubernetes.NewRenewer(
client,
spec.VaultAddr,
spec.VaultKubeRole,
spec.VaultAuthMount,
)
err := renewer.Renew(ctx)
if err != nil {
logrus.Fatalln(err)
}
client.SetToken(token.Token)
spec.VaultTTL = token.TTL
}

http.Handle("/", secret.Handler(
spec.Secret,
plugin.New(client),
logrus.StandardLogger(),
))

var g errgroup.Group
g.Go(func() error {
ctx := context.Background()
return token.NewRenewer(
client, spec.VaultTTL, spec.VaultRenew).Run(ctx)
})
// the vault token needs to be periodically
// refreshed and the kubernetes token has a
// max age of 32 days.
g.Go(func() error {
return renewer.Run(ctx, spec.VaultRenew)
})
} else {
g.Go(func() error {
return token.NewRenewer(
client, spec.VaultTTL, spec.VaultRenew).Run(ctx)
})
}

g.Go(func() error {
logrus.Infof("server listening on address %s", spec.Address)
@@ -5,18 +5,20 @@
package kubernetes

import (
"context"
"fmt"
"io/ioutil"
"time"

"github.com/drone/drone-vault/plugin/token"
"github.com/hashicorp/vault/api"
"github.com/sirupsen/logrus"
)

// Name that identifies the auth method.
const Name = "kubernetes"

// kubernetes token file path.
const path = "/var/run/secrets/kubernetes.io/serviceaccount/token"
const defaultPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"

type (
// kubernetes authorization provider request.
@@ -32,39 +34,81 @@ type (
Lease int `json:"lease_duration"`
}
}

// Renewer renews the Kubernetes token.
Renewer struct {
client *api.Client

address string
mount string
path string
role string
}
)

// Load loads the Vault token using the Kubernetes
// authorization provider.
func Load(address, role, mount string) (*token.Token, error) {
return load(address, role, mount, path)
// NewRenewer returns a new Kubernetes token provider
// that renews the token on expiration.
func NewRenewer(client *api.Client, address, role, mount string) *Renewer {
return &Renewer{
address: address,
client: client,
mount: mount,
role: role,
path: defaultPath,
}
}

func load(address, role, mount, tokenpath string) (*token.Token, error) {
// Renew renews the Vault token.
func (r *Renewer) Renew(ctx context.Context) error {
// create the vault endpoint address.
endpoint := fmt.Sprintf("%s/v1/auth/%s/login", address, mount)
endpoint := fmt.Sprintf("%s/v1/auth/%s/login", r.address, r.mount)

logrus.WithField("path", r.path).
Debugln("kubernetes: reading account token")

// reads the jwt token mounted inside the container.
b, err := ioutil.ReadFile(tokenpath)
b, err := ioutil.ReadFile(r.path)
if err != nil {
return nil, err
logrus.WithError(err).
WithField("path", r.path).
Errorln("kubernetes: cannot read account token")
return err
}

res := &response{}
req := &request{
Jwt: string(b),
Role: role,
Role: r.role,
}

logrus.WithField("endpoint", endpoint).
Debugln("kubernetes: requesting vault token")

err = post(endpoint, req, res)
if err != nil {
return nil, err
logrus.WithError(err).
WithField("endpoint", endpoint).
Errorln("kubernetes: cannot request vault token")
return err
}

// convert the response to the generic token structure
// with the token ttl calculated from the lease.
return &token.Token{
Token: res.Auth.Token,
TTL: time.Duration(res.Auth.Lease) * time.Second,
}, nil
r.client.SetToken(res.Auth.Token)
ttl := time.Duration(res.Auth.Lease) * time.Second

logrus.WithField("ttl", ttl).
Debugln("kubernetes: token received")

return nil
}

// Run performs token renewal at scheduled intervals.
func (r *Renewer) Run(ctx context.Context, renew time.Duration) error {
for {
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(renew):
r.Renew(ctx)
}
}
}
@@ -11,10 +11,8 @@ import (
"net/http/httptest"
"os"
"testing"
"time"

"github.com/drone/drone-vault/plugin/token"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/vault/api"
)

var noContext = context.Background()
@@ -29,22 +27,26 @@ func TestLoad(t *testing.T) {
}))
defer ts.Close()

got, err := load(ts.URL, "dev-role", "kubernetes", "testdata/token.jwt")
client, _ := api.NewClient(nil)

r := NewRenewer(client, ts.URL, "dev-role", "kubernetes")
r.path = "testdata/token.jwt"
err := r.Renew(noContext)
if err != nil {
t.Error(err)
}

want := &token.Token{
Token: "62b858f9-529c-6b26-e0b8-0457b6aacdb4",
TTL: time.Duration(2764800000000000),
}
if diff := cmp.Diff(got, want); diff != "" {
t.Errorf(diff)
want := "62b858f9-529c-6b26-e0b8-0457b6aacdb4"
got := client.Token()
if got != want {
t.Errorf("Want token %s, got %s", want, got)
}
}

func TestLoad_FileError(t *testing.T) {
_, err := load("http://localhost", "dev-role", "kubernetes", "testdata/does-not-exist.jwt")
r := NewRenewer(nil, "http://localhost", "dev-role", "kubernetes")
r.path = "testdata/does-not-exist.jwt"
err := r.Renew(noContext)
if _, ok := err.(*os.PathError); !ok {
t.Errorf("Expect PathError got %v", err)
}
@@ -59,7 +61,9 @@ func TestLoad_RequestError(t *testing.T) {
}))
defer ts.Close()

_, err := load(ts.URL, "dev-role", "kubernetes", "testdata/token.jwt")
r := NewRenewer(nil, ts.URL, "dev-role", "kubernetes")
r.path = "testdata/token.jwt"
err := r.Renew(noContext)
if err == nil {
t.Errorf("Expect request error")
}
@@ -31,7 +31,7 @@ func NewRenewer(client *api.Client, ttl, renew time.Duration) *Renewer {
// Run performs token renewal at scheduled intervals.
func (r *Renewer) Run(ctx context.Context) error {
if r.renew == 0 || r.ttl == 0 {
logrus.Debugf("vault: token rereshing disabled")
logrus.Debugf("vault: token refreshing disabled")
return nil
}

0 comments on commit fd3ba39

Please sign in to comment.