123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- /*
- Copyright 2019 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package routes
- import (
- "net/http"
- restful "github.com/emicklei/go-restful"
- "k8s.io/klog"
- "k8s.io/kubernetes/pkg/serviceaccount"
- )
- // This code is in package routes because many controllers import
- // pkg/serviceaccount, but are not allowed by import-boss to depend on
- // go-restful. All logic that deals with keys is kept in pkg/serviceaccount,
- // and only the rendered JSON is passed into this server.
- const (
- // cacheControl is the value of the Cache-Control header. Overrides the
- // global `private, no-cache` setting.
- headerCacheControl = "Cache-Control"
- cacheControl = "public, max-age=3600" // 1 hour
- // mimeJWKS is the content type of the keyset response
- mimeJWKS = "application/jwk-set+json"
- )
- // OpenIDMetadataServer is an HTTP server for metadata of the KSA token issuer.
- type OpenIDMetadataServer struct {
- configJSON []byte
- keysetJSON []byte
- }
- // NewOpenIDMetadataServer creates a new OpenIDMetadataServer.
- // The issuer is the OIDC issuer; keys are the keys that may be used to sign
- // KSA tokens.
- func NewOpenIDMetadataServer(configJSON, keysetJSON []byte) *OpenIDMetadataServer {
- return &OpenIDMetadataServer{
- configJSON: configJSON,
- keysetJSON: keysetJSON,
- }
- }
- // Install adds this server to the request router c.
- func (s *OpenIDMetadataServer) Install(c *restful.Container) {
- // Configuration WebService
- // Container.Add "will detect duplicate root paths and exit in that case",
- // so we need a root for /.well-known/openid-configuration to avoid conflicts.
- cfg := new(restful.WebService).
- Produces(restful.MIME_JSON)
- cfg.Path(serviceaccount.OpenIDConfigPath).Route(
- cfg.GET("").
- To(fromStandard(s.serveConfiguration)).
- Doc("get service account issuer OpenID configuration, also known as the 'OIDC discovery doc'").
- Operation("getServiceAccountIssuerOpenIDConfiguration").
- // Just include the OK, doesn't look like we include Internal Error in our openapi-spec.
- Returns(http.StatusOK, "OK", ""))
- c.Add(cfg)
- // JWKS WebService
- jwks := new(restful.WebService).
- Produces(mimeJWKS)
- jwks.Path(serviceaccount.JWKSPath).Route(
- jwks.GET("").
- To(fromStandard(s.serveKeys)).
- Doc("get service account issuer OpenID JSON Web Key Set (contains public token verification keys)").
- Operation("getServiceAccountIssuerOpenIDKeyset").
- // Just include the OK, doesn't look like we include Internal Error in our openapi-spec.
- Returns(http.StatusOK, "OK", ""))
- c.Add(jwks)
- }
- // fromStandard provides compatibility between the standard (net/http) handler signature and the restful signature.
- func fromStandard(h http.HandlerFunc) restful.RouteFunction {
- return func(req *restful.Request, resp *restful.Response) {
- h(resp, req.Request)
- }
- }
- func (s *OpenIDMetadataServer) serveConfiguration(w http.ResponseWriter, req *http.Request) {
- w.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON)
- w.Header().Set(headerCacheControl, cacheControl)
- if _, err := w.Write(s.configJSON); err != nil {
- klog.Errorf("failed to write service account issuer metadata response: %v", err)
- return
- }
- }
- func (s *OpenIDMetadataServer) serveKeys(w http.ResponseWriter, req *http.Request) {
- // Per RFC7517 : https://tools.ietf.org/html/rfc7517#section-8.5.1
- w.Header().Set(restful.HEADER_ContentType, mimeJWKS)
- w.Header().Set(headerCacheControl, cacheControl)
- if _, err := w.Write(s.keysetJSON); err != nil {
- klog.Errorf("failed to write service account issuer JWKS response: %v", err)
- return
- }
- }
|