Skip to content

Commit 245b6a5

Browse files
committed
fix: support for service account bound tokens expiration
Signed-off-by: Pedro Parra Ortega <parraortega.pedro@gmail.com> chore: added missing file Signed-off-by: Pedro Parra Ortega <parraortega.pedro@gmail.com> chore: lint Signed-off-by: Pedro Parra Ortega <parraortega.pedro@gmail.com> chore: lint file Signed-off-by: Pedro Parra Ortega <parraortega.pedro@gmail.com>
1 parent 11b2d1c commit 245b6a5

File tree

5 files changed

+46
-5
lines changed

5 files changed

+46
-5
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.21
44

55
require (
66
github.com/go-logr/logr v1.4.1
7+
github.com/golang-jwt/jwt/v5 v5.2.1
78
github.com/gorilla/handlers v1.5.2
89
github.com/gorilla/mux v1.8.1
910
github.com/pkg/errors v0.9.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
6262
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
6363
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
6464
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
65+
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
66+
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
6567
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
6668
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
6769
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=

internal/options/kube.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ func (k kubeOpts) BearerToken() string {
6464
return k.config.BearerToken
6565
}
6666

67+
func (k kubeOpts) BearerTokenFile() string {
68+
return k.config.BearerTokenFile
69+
}
70+
6771
func (k kubeOpts) KubernetesControlPlaneURL() *url.URL {
6872
return &k.url
6973
}

internal/options/listener.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type ListenerOpts interface {
1919
ImpersonationGroupsRegexp() *regexp.Regexp
2020
PreferredUsernameClaim() string
2121
ReverseProxyTransport() (*http.Transport, error)
22+
BearerTokenFile() string
2223
BearerToken() string
2324
SkipImpersonationReview() bool
2425
}

internal/webserver/webserver.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ import (
1111
"net/http"
1212
"net/http/httputil"
1313
"net/textproto"
14+
"os"
1415
"regexp"
1516
"strings"
1617
"time"
1718

1819
"github.com/go-logr/logr"
20+
"github.com/golang-jwt/jwt/v5"
1921
"github.com/gorilla/handlers"
2022
"github.com/gorilla/mux"
2123
"github.com/pkg/errors"
@@ -80,7 +82,9 @@ func NewKubeFilter(opts options.ListenerOpts, srv options.ServerOptions, gates f
8082
impersonationGroupsRegexp: opts.ImpersonationGroupsRegexp(),
8183
skipImpersonationReview: opts.SkipImpersonationReview(),
8284
reverseProxy: reverseProxy,
85+
bearerTokenFile: opts.BearerTokenFile(),
8386
bearerToken: opts.BearerToken(),
87+
bearerTokenExpirationTime: bearerExpirationTime(opts.BearerToken()),
8488
usernameClaimField: opts.PreferredUsernameClaim(),
8589
serverOptions: srv,
8690
log: ctrl.Log.WithName("proxy"),
@@ -97,6 +101,8 @@ type kubeFilter struct {
97101
skipImpersonationReview bool
98102
reverseProxy *httputil.ReverseProxy
99103
bearerToken string
104+
bearerTokenFile string
105+
bearerTokenExpirationTime int64
100106
usernameClaimField string
101107
serverOptions options.ServerOptions
102108
log logr.Logger
@@ -180,9 +186,9 @@ func (n *kubeFilter) handleRequest(request *http.Request, selector labels.Select
180186
n.log.V(4).Info("updating RawQuery", "query", q.Encode())
181187
request.URL.RawQuery = q.Encode()
182188

183-
if len(n.bearerToken) > 0 {
184-
n.log.V(4).Info("Updating the token", "token", n.bearerToken)
185-
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", n.bearerToken))
189+
if len(n.BearerToken()) > 0 {
190+
n.log.V(4).Info("Updating the token", "token", n.BearerToken())
191+
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", n.BearerToken()))
186192
}
187193
}
188194

@@ -203,8 +209,8 @@ func (n *kubeFilter) impersonateHandler(writer http.ResponseWriter, request *htt
203209

204210
n.log.V(4).Info("impersonating for the current request", "username", username, "groups", groups, "uri", request.URL.Path)
205211

206-
if len(n.bearerToken) > 0 {
207-
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", n.bearerToken))
212+
if len(n.BearerToken()) > 0 {
213+
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", n.BearerToken()))
208214
}
209215
// Dropping malicious header connection
210216
// https://github.com/projectcapsule/capsule-proxy/issues/188
@@ -502,3 +508,30 @@ func (n *kubeFilter) removingHopByHopHeaders(request *http.Request) {
502508

503509
request.Header.Del(connectionHeaderName)
504510
}
511+
512+
func (n *kubeFilter) BearerToken() string {
513+
tm := time.Unix(n.bearerTokenExpirationTime, 0)
514+
if !tm.After(time.Now()) {
515+
n.log.V(5).Info("Token expired. Reading new token from file", "token", n.bearerToken, "token file", n.bearerTokenFile)
516+
token, _ := os.ReadFile(n.bearerTokenFile)
517+
n.bearerToken = string(token)
518+
n.bearerTokenExpirationTime = bearerExpirationTime(string(token))
519+
}
520+
521+
return n.bearerToken
522+
}
523+
524+
func bearerExpirationTime(tokenString string) int64 {
525+
token, _, _ := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{})
526+
claims, _ := token.Claims.(jwt.MapClaims)
527+
528+
var mil int64
529+
switch iat := claims["exp"].(type) {
530+
case float64:
531+
mil = int64(iat)
532+
case json.Number:
533+
mil, _ = iat.Int64()
534+
}
535+
536+
return mil
537+
}

0 commit comments

Comments
 (0)