genericapiserver.go 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package genericapiserver
  14. import (
  15. "crypto/tls"
  16. "fmt"
  17. "net"
  18. "net/http"
  19. "net/http/pprof"
  20. "os"
  21. "path"
  22. "regexp"
  23. "sort"
  24. "strconv"
  25. "strings"
  26. "time"
  27. systemd "github.com/coreos/go-systemd/daemon"
  28. "github.com/emicklei/go-restful"
  29. "github.com/emicklei/go-restful/swagger"
  30. "github.com/golang/glog"
  31. "gopkg.in/natefinch/lumberjack.v2"
  32. "github.com/go-openapi/spec"
  33. "k8s.io/kubernetes/pkg/admission"
  34. "k8s.io/kubernetes/pkg/api"
  35. "k8s.io/kubernetes/pkg/api/rest"
  36. "k8s.io/kubernetes/pkg/api/unversioned"
  37. "k8s.io/kubernetes/pkg/apimachinery"
  38. "k8s.io/kubernetes/pkg/apimachinery/registered"
  39. "k8s.io/kubernetes/pkg/apiserver"
  40. "k8s.io/kubernetes/pkg/apiserver/audit"
  41. "k8s.io/kubernetes/pkg/auth/authenticator"
  42. "k8s.io/kubernetes/pkg/auth/authorizer"
  43. "k8s.io/kubernetes/pkg/auth/handlers"
  44. "k8s.io/kubernetes/pkg/cloudprovider"
  45. "k8s.io/kubernetes/pkg/genericapiserver/openapi"
  46. "k8s.io/kubernetes/pkg/genericapiserver/options"
  47. genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
  48. "k8s.io/kubernetes/pkg/registry/generic"
  49. "k8s.io/kubernetes/pkg/registry/generic/registry"
  50. ipallocator "k8s.io/kubernetes/pkg/registry/service/ipallocator"
  51. "k8s.io/kubernetes/pkg/runtime"
  52. "k8s.io/kubernetes/pkg/ui"
  53. "k8s.io/kubernetes/pkg/util"
  54. "k8s.io/kubernetes/pkg/util/async"
  55. "k8s.io/kubernetes/pkg/util/crypto"
  56. utilnet "k8s.io/kubernetes/pkg/util/net"
  57. utilruntime "k8s.io/kubernetes/pkg/util/runtime"
  58. "k8s.io/kubernetes/pkg/util/sets"
  59. )
  60. const globalTimeout = time.Minute
  61. // Info about an API group.
  62. type APIGroupInfo struct {
  63. GroupMeta apimachinery.GroupMeta
  64. // Info about the resources in this group. Its a map from version to resource to the storage.
  65. VersionedResourcesStorageMap map[string]map[string]rest.Storage
  66. // True, if this is the legacy group ("/v1").
  67. IsLegacyGroup bool
  68. // OptionsExternalVersion controls the APIVersion used for common objects in the
  69. // schema like api.Status, api.DeleteOptions, and api.ListOptions. Other implementors may
  70. // define a version "v1beta1" but want to use the Kubernetes "v1" internal objects.
  71. // If nil, defaults to groupMeta.GroupVersion.
  72. // TODO: Remove this when https://github.com/kubernetes/kubernetes/issues/19018 is fixed.
  73. OptionsExternalVersion *unversioned.GroupVersion
  74. // Scheme includes all of the types used by this group and how to convert between them (or
  75. // to convert objects from outside of this group that are accepted in this API).
  76. // TODO: replace with interfaces
  77. Scheme *runtime.Scheme
  78. // NegotiatedSerializer controls how this group encodes and decodes data
  79. NegotiatedSerializer runtime.NegotiatedSerializer
  80. // ParameterCodec performs conversions for query parameters passed to API calls
  81. ParameterCodec runtime.ParameterCodec
  82. // SubresourceGroupVersionKind contains the GroupVersionKind overrides for each subresource that is
  83. // accessible from this API group version. The GroupVersionKind is that of the external version of
  84. // the subresource. The key of this map should be the path of the subresource. The keys here should
  85. // match the keys in the Storage map above for subresources.
  86. SubresourceGroupVersionKind map[string]unversioned.GroupVersionKind
  87. }
  88. // Config is a structure used to configure a GenericAPIServer.
  89. type Config struct {
  90. // The storage factory for other objects
  91. StorageFactory StorageFactory
  92. AuditLogPath string
  93. AuditLogMaxAge int
  94. AuditLogMaxBackups int
  95. AuditLogMaxSize int
  96. // allow downstream consumers to disable the core controller loops
  97. EnableLogsSupport bool
  98. EnableUISupport bool
  99. // Allow downstream consumers to disable swagger.
  100. // This includes returning the generated swagger spec at /swaggerapi and swagger ui at /swagger-ui.
  101. EnableSwaggerSupport bool
  102. // Allow downstream consumers to disable swagger ui.
  103. // Note that this is ignored if either EnableSwaggerSupport or EnableUISupport is false.
  104. EnableSwaggerUI bool
  105. // Allows api group versions or specific resources to be conditionally enabled/disabled.
  106. APIResourceConfigSource APIResourceConfigSource
  107. // allow downstream consumers to disable the index route
  108. EnableIndex bool
  109. EnableProfiling bool
  110. EnableWatchCache bool
  111. APIPrefix string
  112. APIGroupPrefix string
  113. CorsAllowedOriginList []string
  114. Authenticator authenticator.Request
  115. // TODO(roberthbailey): Remove once the server no longer supports http basic auth.
  116. SupportsBasicAuth bool
  117. Authorizer authorizer.Authorizer
  118. AdmissionControl admission.Interface
  119. MasterServiceNamespace string
  120. // TODO(ericchiang): Determine if policy escalation checks should be an admission controller.
  121. AuthorizerRBACSuperUser string
  122. // Map requests to contexts. Exported so downstream consumers can provider their own mappers
  123. RequestContextMapper api.RequestContextMapper
  124. // Required, the interface for serializing and converting objects to and from the wire
  125. Serializer runtime.NegotiatedSerializer
  126. // If specified, all web services will be registered into this container
  127. RestfulContainer *restful.Container
  128. // If specified, requests will be allocated a random timeout between this value, and twice this value.
  129. // Note that it is up to the request handlers to ignore or honor this timeout. In seconds.
  130. MinRequestTimeout int
  131. // Number of masters running; all masters must be started with the
  132. // same value for this field. (Numbers > 1 currently untested.)
  133. MasterCount int
  134. // The port on PublicAddress where a read-write server will be installed.
  135. // Defaults to 6443 if not set.
  136. ReadWritePort int
  137. // ExternalHost is the host name to use for external (public internet) facing URLs (e.g. Swagger)
  138. ExternalHost string
  139. // PublicAddress is the IP address where members of the cluster (kubelet,
  140. // kube-proxy, services, etc.) can reach the GenericAPIServer.
  141. // If nil or 0.0.0.0, the host's default interface will be used.
  142. PublicAddress net.IP
  143. // Control the interval that pod, node IP, and node heath status caches
  144. // expire.
  145. CacheTimeout time.Duration
  146. // The range of IPs to be assigned to services with type=ClusterIP or greater
  147. ServiceClusterIPRange *net.IPNet
  148. // The IP address for the GenericAPIServer service (must be inside ServiceClusterIPRange)
  149. ServiceReadWriteIP net.IP
  150. // Port for the apiserver service.
  151. ServiceReadWritePort int
  152. // The range of ports to be assigned to services with type=NodePort or greater
  153. ServiceNodePortRange utilnet.PortRange
  154. // Used to customize default proxy dial/tls options
  155. ProxyDialer apiserver.ProxyDialerFunc
  156. ProxyTLSClientConfig *tls.Config
  157. // Additional ports to be exposed on the GenericAPIServer service
  158. // extraServicePorts is injectable in the event that more ports
  159. // (other than the default 443/tcp) are exposed on the GenericAPIServer
  160. // and those ports need to be load balanced by the GenericAPIServer
  161. // service because this pkg is linked by out-of-tree projects
  162. // like openshift which want to use the GenericAPIServer but also do
  163. // more stuff.
  164. ExtraServicePorts []api.ServicePort
  165. // Additional ports to be exposed on the GenericAPIServer endpoints
  166. // Port names should align with ports defined in ExtraServicePorts
  167. ExtraEndpointPorts []api.EndpointPort
  168. KubernetesServiceNodePort int
  169. // EnableOpenAPISupport enables OpenAPI support. Allow downstream customers to disable OpenAPI spec.
  170. EnableOpenAPISupport bool
  171. // OpenAPIInfo will be directly available as Info section of Open API spec.
  172. OpenAPIInfo spec.Info
  173. // OpenAPIDefaultResponse will be used if an web service operation does not have any responses listed.
  174. OpenAPIDefaultResponse spec.Response
  175. }
  176. // GenericAPIServer contains state for a Kubernetes cluster api server.
  177. type GenericAPIServer struct {
  178. // "Inputs", Copied from Config
  179. ServiceClusterIPRange *net.IPNet
  180. ServiceNodePortRange utilnet.PortRange
  181. cacheTimeout time.Duration
  182. MinRequestTimeout time.Duration
  183. mux apiserver.Mux
  184. MuxHelper *apiserver.MuxHelper
  185. HandlerContainer *restful.Container
  186. RootWebService *restful.WebService
  187. enableLogsSupport bool
  188. enableUISupport bool
  189. enableSwaggerSupport bool
  190. enableSwaggerUI bool
  191. enableProfiling bool
  192. enableWatchCache bool
  193. APIPrefix string
  194. APIGroupPrefix string
  195. corsAllowedOriginList []string
  196. authenticator authenticator.Request
  197. authorizer authorizer.Authorizer
  198. AdmissionControl admission.Interface
  199. MasterCount int
  200. RequestContextMapper api.RequestContextMapper
  201. // ExternalAddress is the address (hostname or IP and port) that should be used in
  202. // external (public internet) URLs for this GenericAPIServer.
  203. ExternalAddress string
  204. // ClusterIP is the IP address of the GenericAPIServer within the cluster.
  205. ClusterIP net.IP
  206. PublicReadWritePort int
  207. ServiceReadWriteIP net.IP
  208. ServiceReadWritePort int
  209. masterServices *async.Runner
  210. ExtraServicePorts []api.ServicePort
  211. ExtraEndpointPorts []api.EndpointPort
  212. // storage contains the RESTful endpoints exposed by this GenericAPIServer
  213. storage map[string]rest.Storage
  214. // Serializer controls how common API objects not in a group/version prefix are serialized for this server.
  215. // Individual APIGroups may define their own serializers.
  216. Serializer runtime.NegotiatedSerializer
  217. // "Outputs"
  218. Handler http.Handler
  219. InsecureHandler http.Handler
  220. // Used for custom proxy dialing, and proxy TLS options
  221. ProxyTransport http.RoundTripper
  222. KubernetesServiceNodePort int
  223. // Map storing information about all groups to be exposed in discovery response.
  224. // The map is from name to the group.
  225. apiGroupsForDiscovery map[string]unversioned.APIGroup
  226. // See Config.$name for documentation of these flags
  227. enableOpenAPISupport bool
  228. openAPIInfo spec.Info
  229. openAPIDefaultResponse spec.Response
  230. }
  231. func (s *GenericAPIServer) StorageDecorator() generic.StorageDecorator {
  232. if s.enableWatchCache {
  233. return registry.StorageWithCacher
  234. }
  235. return generic.UndecoratedStorage
  236. }
  237. // setDefaults fills in any fields not set that are required to have valid data.
  238. func setDefaults(c *Config) {
  239. if c.ServiceClusterIPRange == nil {
  240. defaultNet := "10.0.0.0/24"
  241. glog.Warningf("Network range for service cluster IPs is unspecified. Defaulting to %v.", defaultNet)
  242. _, serviceClusterIPRange, err := net.ParseCIDR(defaultNet)
  243. if err != nil {
  244. glog.Fatalf("Unable to parse CIDR: %v", err)
  245. }
  246. if size := ipallocator.RangeSize(serviceClusterIPRange); size < 8 {
  247. glog.Fatalf("The service cluster IP range must be at least %d IP addresses", 8)
  248. }
  249. c.ServiceClusterIPRange = serviceClusterIPRange
  250. }
  251. if c.ServiceReadWriteIP == nil {
  252. // Select the first valid IP from ServiceClusterIPRange to use as the GenericAPIServer service IP.
  253. serviceReadWriteIP, err := ipallocator.GetIndexedIP(c.ServiceClusterIPRange, 1)
  254. if err != nil {
  255. glog.Fatalf("Failed to generate service read-write IP for GenericAPIServer service: %v", err)
  256. }
  257. glog.V(4).Infof("Setting GenericAPIServer service IP to %q (read-write).", serviceReadWriteIP)
  258. c.ServiceReadWriteIP = serviceReadWriteIP
  259. }
  260. if c.ServiceReadWritePort == 0 {
  261. c.ServiceReadWritePort = 443
  262. }
  263. if c.ServiceNodePortRange.Size == 0 {
  264. // TODO: Currently no way to specify an empty range (do we need to allow this?)
  265. // We should probably allow this for clouds that don't require NodePort to do load-balancing (GCE)
  266. // but then that breaks the strict nestedness of ServiceType.
  267. // Review post-v1
  268. c.ServiceNodePortRange = options.DefaultServiceNodePortRange
  269. glog.Infof("Node port range unspecified. Defaulting to %v.", c.ServiceNodePortRange)
  270. }
  271. if c.MasterCount == 0 {
  272. // Clearly, there will be at least one GenericAPIServer.
  273. c.MasterCount = 1
  274. }
  275. if c.ReadWritePort == 0 {
  276. c.ReadWritePort = 6443
  277. }
  278. if c.CacheTimeout == 0 {
  279. c.CacheTimeout = 5 * time.Second
  280. }
  281. if c.RequestContextMapper == nil {
  282. c.RequestContextMapper = api.NewRequestContextMapper()
  283. }
  284. if len(c.ExternalHost) == 0 && c.PublicAddress != nil {
  285. hostAndPort := c.PublicAddress.String()
  286. if c.ReadWritePort != 0 {
  287. hostAndPort = net.JoinHostPort(hostAndPort, strconv.Itoa(c.ReadWritePort))
  288. }
  289. c.ExternalHost = hostAndPort
  290. }
  291. }
  292. // New returns a new instance of GenericAPIServer from the given config.
  293. // Certain config fields will be set to a default value if unset,
  294. // including:
  295. // ServiceClusterIPRange
  296. // ServiceNodePortRange
  297. // MasterCount
  298. // ReadWritePort
  299. // PublicAddress
  300. // Public fields:
  301. // Handler -- The returned GenericAPIServer has a field TopHandler which is an
  302. // http.Handler which handles all the endpoints provided by the GenericAPIServer,
  303. // including the API, the UI, and miscellaneous debugging endpoints. All
  304. // these are subject to authorization and authentication.
  305. // InsecureHandler -- an http.Handler which handles all the same
  306. // endpoints as Handler, but no authorization and authentication is done.
  307. // Public methods:
  308. // HandleWithAuth -- Allows caller to add an http.Handler for an endpoint
  309. // that uses the same authentication and authorization (if any is configured)
  310. // as the GenericAPIServer's built-in endpoints.
  311. // If the caller wants to add additional endpoints not using the GenericAPIServer's
  312. // auth, then the caller should create a handler for those endpoints, which delegates the
  313. // any unhandled paths to "Handler".
  314. func New(c *Config) (*GenericAPIServer, error) {
  315. if c.Serializer == nil {
  316. return nil, fmt.Errorf("Genericapiserver.New() called with config.Serializer == nil")
  317. }
  318. setDefaults(c)
  319. s := &GenericAPIServer{
  320. ServiceClusterIPRange: c.ServiceClusterIPRange,
  321. ServiceNodePortRange: c.ServiceNodePortRange,
  322. RootWebService: new(restful.WebService),
  323. enableLogsSupport: c.EnableLogsSupport,
  324. enableUISupport: c.EnableUISupport,
  325. enableSwaggerSupport: c.EnableSwaggerSupport,
  326. enableSwaggerUI: c.EnableSwaggerUI,
  327. enableProfiling: c.EnableProfiling,
  328. enableWatchCache: c.EnableWatchCache,
  329. APIPrefix: c.APIPrefix,
  330. APIGroupPrefix: c.APIGroupPrefix,
  331. corsAllowedOriginList: c.CorsAllowedOriginList,
  332. authenticator: c.Authenticator,
  333. authorizer: c.Authorizer,
  334. AdmissionControl: c.AdmissionControl,
  335. RequestContextMapper: c.RequestContextMapper,
  336. Serializer: c.Serializer,
  337. cacheTimeout: c.CacheTimeout,
  338. MinRequestTimeout: time.Duration(c.MinRequestTimeout) * time.Second,
  339. MasterCount: c.MasterCount,
  340. ExternalAddress: c.ExternalHost,
  341. ClusterIP: c.PublicAddress,
  342. PublicReadWritePort: c.ReadWritePort,
  343. ServiceReadWriteIP: c.ServiceReadWriteIP,
  344. ServiceReadWritePort: c.ServiceReadWritePort,
  345. ExtraServicePorts: c.ExtraServicePorts,
  346. ExtraEndpointPorts: c.ExtraEndpointPorts,
  347. KubernetesServiceNodePort: c.KubernetesServiceNodePort,
  348. apiGroupsForDiscovery: map[string]unversioned.APIGroup{},
  349. enableOpenAPISupport: c.EnableOpenAPISupport,
  350. openAPIInfo: c.OpenAPIInfo,
  351. openAPIDefaultResponse: c.OpenAPIDefaultResponse,
  352. }
  353. if c.RestfulContainer != nil {
  354. s.mux = c.RestfulContainer.ServeMux
  355. s.HandlerContainer = c.RestfulContainer
  356. } else {
  357. mux := http.NewServeMux()
  358. s.mux = mux
  359. s.HandlerContainer = NewHandlerContainer(mux, c.Serializer)
  360. }
  361. // Use CurlyRouter to be able to use regular expressions in paths. Regular expressions are required in paths for example for proxy (where the path is proxy/{kind}/{name}/{*})
  362. s.HandlerContainer.Router(restful.CurlyRouter{})
  363. s.MuxHelper = &apiserver.MuxHelper{Mux: s.mux, RegisteredPaths: []string{}}
  364. s.init(c)
  365. return s, nil
  366. }
  367. func (s *GenericAPIServer) NewRequestInfoResolver() *apiserver.RequestInfoResolver {
  368. return &apiserver.RequestInfoResolver{
  369. APIPrefixes: sets.NewString(strings.Trim(s.APIPrefix, "/"), strings.Trim(s.APIGroupPrefix, "/")), // all possible API prefixes
  370. GrouplessAPIPrefixes: sets.NewString(strings.Trim(s.APIPrefix, "/")), // APIPrefixes that won't have groups (legacy)
  371. }
  372. }
  373. // HandleWithAuth adds an http.Handler for pattern to an http.ServeMux
  374. // Applies the same authentication and authorization (if any is configured)
  375. // to the request is used for the GenericAPIServer's built-in endpoints.
  376. func (s *GenericAPIServer) HandleWithAuth(pattern string, handler http.Handler) {
  377. // TODO: Add a way for plugged-in endpoints to translate their
  378. // URLs into attributes that an Authorizer can understand, and have
  379. // sensible policy defaults for plugged-in endpoints. This will be different
  380. // for generic endpoints versus REST object endpoints.
  381. // TODO: convert to go-restful
  382. s.MuxHelper.Handle(pattern, handler)
  383. }
  384. // HandleFuncWithAuth adds an http.Handler for pattern to an http.ServeMux
  385. // Applies the same authentication and authorization (if any is configured)
  386. // to the request is used for the GenericAPIServer's built-in endpoints.
  387. func (s *GenericAPIServer) HandleFuncWithAuth(pattern string, handler func(http.ResponseWriter, *http.Request)) {
  388. // TODO: convert to go-restful
  389. s.MuxHelper.HandleFunc(pattern, handler)
  390. }
  391. func NewHandlerContainer(mux *http.ServeMux, s runtime.NegotiatedSerializer) *restful.Container {
  392. container := restful.NewContainer()
  393. container.ServeMux = mux
  394. apiserver.InstallRecoverHandler(s, container)
  395. return container
  396. }
  397. // init initializes GenericAPIServer.
  398. func (s *GenericAPIServer) init(c *Config) {
  399. if c.ProxyDialer != nil || c.ProxyTLSClientConfig != nil {
  400. s.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{
  401. Dial: c.ProxyDialer,
  402. TLSClientConfig: c.ProxyTLSClientConfig,
  403. })
  404. }
  405. // Register root handler.
  406. // We do not register this using restful Webservice since we do not want to surface this in api docs.
  407. // Allow GenericAPIServer to be embedded in contexts which already have something registered at the root
  408. if c.EnableIndex {
  409. s.mux.HandleFunc("/", apiserver.IndexHandler(s.HandlerContainer, s.MuxHelper))
  410. }
  411. if c.EnableLogsSupport {
  412. apiserver.InstallLogsSupport(s.MuxHelper, s.HandlerContainer)
  413. }
  414. if c.EnableUISupport {
  415. ui.InstallSupport(s.MuxHelper, s.enableSwaggerSupport && s.enableSwaggerUI)
  416. }
  417. if c.EnableProfiling {
  418. s.mux.HandleFunc("/debug/pprof/", pprof.Index)
  419. s.mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
  420. s.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
  421. }
  422. apiserver.InstallVersionHandler(s.MuxHelper, s.HandlerContainer)
  423. handler := http.Handler(s.mux.(*http.ServeMux))
  424. // TODO: handle CORS and auth using go-restful
  425. // See github.com/emicklei/go-restful/blob/master/examples/restful-CORS-filter.go, and
  426. // github.com/emicklei/go-restful/blob/master/examples/restful-basic-authentication.go
  427. if len(c.CorsAllowedOriginList) > 0 {
  428. allowedOriginRegexps, err := util.CompileRegexps(c.CorsAllowedOriginList)
  429. if err != nil {
  430. glog.Fatalf("Invalid CORS allowed origin, --cors-allowed-origins flag was set to %v - %v", strings.Join(c.CorsAllowedOriginList, ","), err)
  431. }
  432. handler = apiserver.CORS(handler, allowedOriginRegexps, nil, nil, "true")
  433. }
  434. s.InsecureHandler = handler
  435. attributeGetter := apiserver.NewRequestAttributeGetter(s.RequestContextMapper, s.NewRequestInfoResolver())
  436. handler = apiserver.WithAuthorizationCheck(handler, attributeGetter, s.authorizer)
  437. if len(c.AuditLogPath) != 0 {
  438. // audit handler must comes before the impersonationFilter to read the original user
  439. writer := &lumberjack.Logger{
  440. Filename: c.AuditLogPath,
  441. MaxAge: c.AuditLogMaxAge,
  442. MaxBackups: c.AuditLogMaxBackups,
  443. MaxSize: c.AuditLogMaxSize,
  444. }
  445. handler = audit.WithAudit(handler, s.RequestContextMapper, writer)
  446. defer writer.Close()
  447. }
  448. handler = apiserver.WithImpersonation(handler, s.RequestContextMapper, s.authorizer)
  449. // Install Authenticator
  450. if c.Authenticator != nil {
  451. authenticatedHandler, err := handlers.NewRequestAuthenticator(s.RequestContextMapper, c.Authenticator, handlers.Unauthorized(c.SupportsBasicAuth), handler)
  452. if err != nil {
  453. glog.Fatalf("Could not initialize authenticator: %v", err)
  454. }
  455. handler = authenticatedHandler
  456. }
  457. // TODO: Make this optional? Consumers of GenericAPIServer depend on this currently.
  458. s.Handler = handler
  459. // After all wrapping is done, put a context filter around both handlers
  460. var err error
  461. handler, err = api.NewRequestContextFilter(s.RequestContextMapper, s.Handler)
  462. if err != nil {
  463. glog.Fatalf("Could not initialize request context filter for s.Handler: %v", err)
  464. }
  465. s.Handler = handler
  466. handler, err = api.NewRequestContextFilter(s.RequestContextMapper, s.InsecureHandler)
  467. if err != nil {
  468. glog.Fatalf("Could not initialize request context filter for s.InsecureHandler: %v", err)
  469. }
  470. s.InsecureHandler = handler
  471. s.installGroupsDiscoveryHandler()
  472. }
  473. // Exposes the given group versions in API. Helper method to install multiple group versions at once.
  474. func (s *GenericAPIServer) InstallAPIGroups(groupsInfo []APIGroupInfo) error {
  475. for _, apiGroupInfo := range groupsInfo {
  476. if err := s.InstallAPIGroup(&apiGroupInfo); err != nil {
  477. return err
  478. }
  479. }
  480. return nil
  481. }
  482. // Installs handler at /apis to list all group versions for discovery
  483. func (s *GenericAPIServer) installGroupsDiscoveryHandler() {
  484. apiserver.AddApisWebService(s.Serializer, s.HandlerContainer, s.APIGroupPrefix, func(req *restful.Request) []unversioned.APIGroup {
  485. // Return the list of supported groups in sorted order (to have a deterministic order).
  486. groups := []unversioned.APIGroup{}
  487. groupNames := make([]string, len(s.apiGroupsForDiscovery))
  488. var i int = 0
  489. for groupName := range s.apiGroupsForDiscovery {
  490. groupNames[i] = groupName
  491. i++
  492. }
  493. sort.Strings(groupNames)
  494. for _, groupName := range groupNames {
  495. apiGroup := s.apiGroupsForDiscovery[groupName]
  496. // Add ServerAddressByClientCIDRs.
  497. apiGroup.ServerAddressByClientCIDRs = s.getServerAddressByClientCIDRs(req.Request)
  498. groups = append(groups, apiGroup)
  499. }
  500. return groups
  501. })
  502. }
  503. func NewConfig(options *options.ServerRunOptions) *Config {
  504. return &Config{
  505. APIGroupPrefix: options.APIGroupPrefix,
  506. APIPrefix: options.APIPrefix,
  507. CorsAllowedOriginList: options.CorsAllowedOriginList,
  508. AuditLogPath: options.AuditLogPath,
  509. AuditLogMaxAge: options.AuditLogMaxAge,
  510. AuditLogMaxBackups: options.AuditLogMaxBackups,
  511. AuditLogMaxSize: options.AuditLogMaxSize,
  512. EnableIndex: true,
  513. EnableLogsSupport: options.EnableLogsSupport,
  514. EnableProfiling: options.EnableProfiling,
  515. EnableSwaggerSupport: true,
  516. EnableSwaggerUI: options.EnableSwaggerUI,
  517. EnableUISupport: true,
  518. EnableWatchCache: options.EnableWatchCache,
  519. ExternalHost: options.ExternalHost,
  520. KubernetesServiceNodePort: options.KubernetesServiceNodePort,
  521. MasterCount: options.MasterCount,
  522. MinRequestTimeout: options.MinRequestTimeout,
  523. PublicAddress: options.AdvertiseAddress,
  524. ReadWritePort: options.SecurePort,
  525. ServiceClusterIPRange: &options.ServiceClusterIPRange,
  526. ServiceNodePortRange: options.ServiceNodePortRange,
  527. EnableOpenAPISupport: true,
  528. OpenAPIDefaultResponse: spec.Response{
  529. ResponseProps: spec.ResponseProps{
  530. Description: "Default Response."}},
  531. OpenAPIInfo: spec.Info{
  532. InfoProps: spec.InfoProps{
  533. Title: "Generic API Server",
  534. Version: "unversioned",
  535. },
  536. },
  537. }
  538. }
  539. func DefaultAndValidateRunOptions(options *options.ServerRunOptions) {
  540. genericvalidation.ValidateRunOptions(options)
  541. // If advertise-address is not specified, use bind-address. If bind-address
  542. // is not usable (unset, 0.0.0.0, or loopback), we will use the host's default
  543. // interface as valid public addr for master (see: util/net#ValidPublicAddrForMaster)
  544. if options.AdvertiseAddress == nil || options.AdvertiseAddress.IsUnspecified() {
  545. hostIP, err := utilnet.ChooseBindAddress(options.BindAddress)
  546. if err != nil {
  547. glog.Fatalf("Unable to find suitable network address.error='%v' . "+
  548. "Try to set the AdvertiseAddress directly or provide a valid BindAddress to fix this.", err)
  549. }
  550. options.AdvertiseAddress = hostIP
  551. }
  552. glog.Infof("Will report %v as public IP address.", options.AdvertiseAddress)
  553. // Set default value for ExternalHost if not specified.
  554. if len(options.ExternalHost) == 0 {
  555. // TODO: extend for other providers
  556. if options.CloudProvider == "gce" {
  557. cloud, err := cloudprovider.InitCloudProvider(options.CloudProvider, options.CloudConfigFile)
  558. if err != nil {
  559. glog.Fatalf("Cloud provider could not be initialized: %v", err)
  560. }
  561. instances, supported := cloud.Instances()
  562. if !supported {
  563. glog.Fatalf("GCE cloud provider has no instances. this shouldn't happen. exiting.")
  564. }
  565. name, err := os.Hostname()
  566. if err != nil {
  567. glog.Fatalf("Failed to get hostname: %v", err)
  568. }
  569. addrs, err := instances.NodeAddresses(name)
  570. if err != nil {
  571. glog.Warningf("Unable to obtain external host address from cloud provider: %v", err)
  572. } else {
  573. for _, addr := range addrs {
  574. if addr.Type == api.NodeExternalIP {
  575. options.ExternalHost = addr.Address
  576. }
  577. }
  578. }
  579. }
  580. }
  581. }
  582. func (s *GenericAPIServer) Run(options *options.ServerRunOptions) {
  583. if s.enableSwaggerSupport {
  584. s.InstallSwaggerAPI()
  585. }
  586. if s.enableOpenAPISupport {
  587. s.InstallOpenAPI()
  588. }
  589. // We serve on 2 ports. See docs/admin/accessing-the-api.md
  590. secureLocation := ""
  591. if options.SecurePort != 0 {
  592. secureLocation = net.JoinHostPort(options.BindAddress.String(), strconv.Itoa(options.SecurePort))
  593. }
  594. insecureLocation := net.JoinHostPort(options.InsecureBindAddress.String(), strconv.Itoa(options.InsecurePort))
  595. var sem chan bool
  596. if options.MaxRequestsInFlight > 0 {
  597. sem = make(chan bool, options.MaxRequestsInFlight)
  598. }
  599. longRunningRE := regexp.MustCompile(options.LongRunningRequestRE)
  600. longRunningRequestCheck := apiserver.BasicLongRunningRequestCheck(longRunningRE, map[string]string{"watch": "true"})
  601. longRunningTimeout := func(req *http.Request) (<-chan time.Time, string) {
  602. // TODO unify this with apiserver.MaxInFlightLimit
  603. if longRunningRequestCheck(req) {
  604. return nil, ""
  605. }
  606. return time.After(globalTimeout), ""
  607. }
  608. if secureLocation != "" {
  609. handler := apiserver.TimeoutHandler(apiserver.RecoverPanics(s.Handler), longRunningTimeout)
  610. secureServer := &http.Server{
  611. Addr: secureLocation,
  612. Handler: apiserver.MaxInFlightLimit(sem, longRunningRequestCheck, handler),
  613. MaxHeaderBytes: 1 << 20,
  614. TLSConfig: &tls.Config{
  615. // Can't use SSLv3 because of POODLE and BEAST
  616. // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
  617. // Can't use TLSv1.1 because of RC4 cipher usage
  618. MinVersion: tls.VersionTLS12,
  619. },
  620. }
  621. if len(options.ClientCAFile) > 0 {
  622. clientCAs, err := crypto.CertPoolFromFile(options.ClientCAFile)
  623. if err != nil {
  624. glog.Fatalf("Unable to load client CA file: %v", err)
  625. }
  626. // Populate PeerCertificates in requests, but don't reject connections without certificates
  627. // This allows certificates to be validated by authenticators, while still allowing other auth types
  628. secureServer.TLSConfig.ClientAuth = tls.RequestClientCert
  629. // Specify allowed CAs for client certificates
  630. secureServer.TLSConfig.ClientCAs = clientCAs
  631. }
  632. glog.Infof("Serving securely on %s", secureLocation)
  633. if options.TLSCertFile == "" && options.TLSPrivateKeyFile == "" {
  634. options.TLSCertFile = path.Join(options.CertDirectory, "apiserver.crt")
  635. options.TLSPrivateKeyFile = path.Join(options.CertDirectory, "apiserver.key")
  636. // TODO (cjcullen): Is ClusterIP the right address to sign a cert with?
  637. alternateIPs := []net.IP{s.ServiceReadWriteIP}
  638. alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"}
  639. // It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless
  640. // alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME")
  641. if !crypto.FoundCertOrKey(options.TLSCertFile, options.TLSPrivateKeyFile) {
  642. if err := crypto.GenerateSelfSignedCert(s.ClusterIP.String(), options.TLSCertFile, options.TLSPrivateKeyFile, alternateIPs, alternateDNS); err != nil {
  643. glog.Errorf("Unable to generate self signed cert: %v", err)
  644. } else {
  645. glog.Infof("Using self-signed cert (%s, %s)", options.TLSCertFile, options.TLSPrivateKeyFile)
  646. }
  647. }
  648. }
  649. go func() {
  650. defer utilruntime.HandleCrash()
  651. for {
  652. // err == systemd.SdNotifyNoSocket when not running on a systemd system
  653. if err := systemd.SdNotify("READY=1\n"); err != nil && err != systemd.SdNotifyNoSocket {
  654. glog.Errorf("Unable to send systemd daemon successful start message: %v\n", err)
  655. }
  656. if err := secureServer.ListenAndServeTLS(options.TLSCertFile, options.TLSPrivateKeyFile); err != nil {
  657. glog.Errorf("Unable to listen for secure (%v); will try again.", err)
  658. }
  659. time.Sleep(15 * time.Second)
  660. }
  661. }()
  662. } else {
  663. // err == systemd.SdNotifyNoSocket when not running on a systemd system
  664. if err := systemd.SdNotify("READY=1\n"); err != nil && err != systemd.SdNotifyNoSocket {
  665. glog.Errorf("Unable to send systemd daemon successful start message: %v\n", err)
  666. }
  667. }
  668. handler := apiserver.TimeoutHandler(apiserver.RecoverPanics(s.InsecureHandler), longRunningTimeout)
  669. http := &http.Server{
  670. Addr: insecureLocation,
  671. Handler: handler,
  672. MaxHeaderBytes: 1 << 20,
  673. }
  674. glog.Infof("Serving insecurely on %s", insecureLocation)
  675. go func() {
  676. defer utilruntime.HandleCrash()
  677. for {
  678. if err := http.ListenAndServe(); err != nil {
  679. glog.Errorf("Unable to listen for insecure (%v); will try again.", err)
  680. }
  681. time.Sleep(15 * time.Second)
  682. }
  683. }()
  684. select {}
  685. }
  686. // Exposes the given group version in API.
  687. func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error {
  688. apiPrefix := s.APIGroupPrefix
  689. if apiGroupInfo.IsLegacyGroup {
  690. apiPrefix = s.APIPrefix
  691. }
  692. // Install REST handlers for all the versions in this group.
  693. apiVersions := []string{}
  694. for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
  695. apiVersions = append(apiVersions, groupVersion.Version)
  696. apiGroupVersion, err := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix)
  697. if err != nil {
  698. return err
  699. }
  700. if apiGroupInfo.OptionsExternalVersion != nil {
  701. apiGroupVersion.OptionsExternalVersion = apiGroupInfo.OptionsExternalVersion
  702. }
  703. if err := apiGroupVersion.InstallREST(s.HandlerContainer); err != nil {
  704. return fmt.Errorf("Unable to setup API %v: %v", apiGroupInfo, err)
  705. }
  706. }
  707. // Install the version handler.
  708. if apiGroupInfo.IsLegacyGroup {
  709. // Add a handler at /api to enumerate the supported api versions.
  710. apiserver.AddApiWebService(s.Serializer, s.HandlerContainer, apiPrefix, func(req *restful.Request) *unversioned.APIVersions {
  711. apiVersionsForDiscovery := unversioned.APIVersions{
  712. ServerAddressByClientCIDRs: s.getServerAddressByClientCIDRs(req.Request),
  713. Versions: apiVersions,
  714. }
  715. return &apiVersionsForDiscovery
  716. })
  717. } else {
  718. // Do not register empty group or empty version. Doing so claims /apis/ for the wrong entity to be returned.
  719. // Catching these here places the error much closer to its origin
  720. if len(apiGroupInfo.GroupMeta.GroupVersion.Group) == 0 {
  721. return fmt.Errorf("cannot register handler with an empty group for %#v", *apiGroupInfo)
  722. }
  723. if len(apiGroupInfo.GroupMeta.GroupVersion.Version) == 0 {
  724. return fmt.Errorf("cannot register handler with an empty version for %#v", *apiGroupInfo)
  725. }
  726. // Add a handler at /apis/<groupName> to enumerate all versions supported by this group.
  727. apiVersionsForDiscovery := []unversioned.GroupVersionForDiscovery{}
  728. for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
  729. apiVersionsForDiscovery = append(apiVersionsForDiscovery, unversioned.GroupVersionForDiscovery{
  730. GroupVersion: groupVersion.String(),
  731. Version: groupVersion.Version,
  732. })
  733. }
  734. preferedVersionForDiscovery := unversioned.GroupVersionForDiscovery{
  735. GroupVersion: apiGroupInfo.GroupMeta.GroupVersion.String(),
  736. Version: apiGroupInfo.GroupMeta.GroupVersion.Version,
  737. }
  738. apiGroup := unversioned.APIGroup{
  739. Name: apiGroupInfo.GroupMeta.GroupVersion.Group,
  740. Versions: apiVersionsForDiscovery,
  741. PreferredVersion: preferedVersionForDiscovery,
  742. }
  743. s.AddAPIGroupForDiscovery(apiGroup)
  744. apiserver.AddGroupWebService(s.Serializer, s.HandlerContainer, apiPrefix+"/"+apiGroup.Name, apiGroup)
  745. }
  746. apiserver.InstallServiceErrorHandler(s.Serializer, s.HandlerContainer, s.NewRequestInfoResolver(), apiVersions)
  747. return nil
  748. }
  749. func (s *GenericAPIServer) AddAPIGroupForDiscovery(apiGroup unversioned.APIGroup) {
  750. s.apiGroupsForDiscovery[apiGroup.Name] = apiGroup
  751. }
  752. func (s *GenericAPIServer) RemoveAPIGroupForDiscovery(groupName string) {
  753. delete(s.apiGroupsForDiscovery, groupName)
  754. }
  755. func (s *GenericAPIServer) getServerAddressByClientCIDRs(req *http.Request) []unversioned.ServerAddressByClientCIDR {
  756. addressCIDRMap := []unversioned.ServerAddressByClientCIDR{
  757. {
  758. ClientCIDR: "0.0.0.0/0",
  759. ServerAddress: s.ExternalAddress,
  760. },
  761. }
  762. // Add internal CIDR if the request came from internal IP.
  763. clientIP := utilnet.GetClientIP(req)
  764. clusterCIDR := s.ServiceClusterIPRange
  765. if clusterCIDR.Contains(clientIP) {
  766. addressCIDRMap = append(addressCIDRMap, unversioned.ServerAddressByClientCIDR{
  767. ClientCIDR: clusterCIDR.String(),
  768. ServerAddress: net.JoinHostPort(s.ServiceReadWriteIP.String(), strconv.Itoa(s.ServiceReadWritePort)),
  769. })
  770. }
  771. return addressCIDRMap
  772. }
  773. func (s *GenericAPIServer) getAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupVersion unversioned.GroupVersion, apiPrefix string) (*apiserver.APIGroupVersion, error) {
  774. storage := make(map[string]rest.Storage)
  775. for k, v := range apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version] {
  776. storage[strings.ToLower(k)] = v
  777. }
  778. version, err := s.newAPIGroupVersion(apiGroupInfo, groupVersion)
  779. version.Root = apiPrefix
  780. version.Storage = storage
  781. return version, err
  782. }
  783. func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupVersion unversioned.GroupVersion) (*apiserver.APIGroupVersion, error) {
  784. return &apiserver.APIGroupVersion{
  785. RequestInfoResolver: s.NewRequestInfoResolver(),
  786. GroupVersion: groupVersion,
  787. ParameterCodec: apiGroupInfo.ParameterCodec,
  788. Serializer: apiGroupInfo.NegotiatedSerializer,
  789. Creater: apiGroupInfo.Scheme,
  790. Convertor: apiGroupInfo.Scheme,
  791. Copier: apiGroupInfo.Scheme,
  792. Typer: apiGroupInfo.Scheme,
  793. SubresourceGroupVersionKind: apiGroupInfo.SubresourceGroupVersionKind,
  794. Linker: apiGroupInfo.GroupMeta.SelfLinker,
  795. Mapper: apiGroupInfo.GroupMeta.RESTMapper,
  796. Admit: s.AdmissionControl,
  797. Context: s.RequestContextMapper,
  798. MinRequestTimeout: s.MinRequestTimeout,
  799. }, nil
  800. }
  801. // getSwaggerConfig returns swagger config shared between SwaggerAPI and OpenAPI spec generators
  802. func (s *GenericAPIServer) getSwaggerConfig() *swagger.Config {
  803. hostAndPort := s.ExternalAddress
  804. protocol := "https://"
  805. webServicesUrl := protocol + hostAndPort
  806. return &swagger.Config{
  807. WebServicesUrl: webServicesUrl,
  808. WebServices: s.HandlerContainer.RegisteredWebServices(),
  809. ApiPath: "/swaggerapi/",
  810. SwaggerPath: "/swaggerui/",
  811. SwaggerFilePath: "/swagger-ui/",
  812. SchemaFormatHandler: func(typeName string) string {
  813. switch typeName {
  814. case "unversioned.Time", "*unversioned.Time":
  815. return "date-time"
  816. }
  817. return ""
  818. },
  819. }
  820. }
  821. // InstallSwaggerAPI installs the /swaggerapi/ endpoint to allow schema discovery
  822. // and traversal. It is optional to allow consumers of the Kubernetes GenericAPIServer to
  823. // register their own web services into the Kubernetes mux prior to initialization
  824. // of swagger, so that other resource types show up in the documentation.
  825. func (s *GenericAPIServer) InstallSwaggerAPI() {
  826. // Enable swagger UI and discovery API
  827. swagger.RegisterSwaggerService(*s.getSwaggerConfig(), s.HandlerContainer)
  828. }
  829. // InstallOpenAPI installs the /swagger.json endpoint to allow new OpenAPI schema discovery.
  830. func (s *GenericAPIServer) InstallOpenAPI() {
  831. openAPIConfig := openapi.Config{
  832. SwaggerConfig: s.getSwaggerConfig(),
  833. IgnorePrefixes: []string{"/swaggerapi"},
  834. Info: &s.openAPIInfo,
  835. DefaultResponse: &s.openAPIDefaultResponse,
  836. }
  837. err := openapi.RegisterOpenAPIService(&openAPIConfig, s.HandlerContainer)
  838. if err != nil {
  839. glog.Fatalf("Failed to generate open api spec: %v", err)
  840. }
  841. }
  842. // NewDefaultAPIGroupInfo returns an APIGroupInfo stubbed with "normal" values
  843. // exposed for easier composition from other packages
  844. func NewDefaultAPIGroupInfo(group string) APIGroupInfo {
  845. groupMeta := registered.GroupOrDie(group)
  846. return APIGroupInfo{
  847. GroupMeta: *groupMeta,
  848. VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},
  849. OptionsExternalVersion: &registered.GroupOrDie(api.GroupName).GroupVersion,
  850. Scheme: api.Scheme,
  851. ParameterCodec: api.ParameterCodec,
  852. NegotiatedSerializer: api.Codecs,
  853. }
  854. }