main.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. Copyright 2018 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 main
  14. import (
  15. "encoding/json"
  16. "flag"
  17. "fmt"
  18. "io/ioutil"
  19. "net/http"
  20. "k8s.io/api/admission/v1beta1"
  21. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  22. "k8s.io/klog"
  23. // TODO: try this library to see if it generates correct json patch
  24. // https://github.com/mattbaird/jsonpatch
  25. )
  26. // toAdmissionResponse is a helper function to create an AdmissionResponse
  27. // with an embedded error
  28. func toAdmissionResponse(err error) *v1beta1.AdmissionResponse {
  29. return &v1beta1.AdmissionResponse{
  30. Result: &metav1.Status{
  31. Message: err.Error(),
  32. },
  33. }
  34. }
  35. // admitFunc is the type we use for all of our validators and mutators
  36. type admitFunc func(v1beta1.AdmissionReview) *v1beta1.AdmissionResponse
  37. // serve handles the http portion of a request prior to handing to an admit
  38. // function
  39. func serve(w http.ResponseWriter, r *http.Request, admit admitFunc) {
  40. var body []byte
  41. if r.Body != nil {
  42. if data, err := ioutil.ReadAll(r.Body); err == nil {
  43. body = data
  44. }
  45. }
  46. // verify the content type is accurate
  47. contentType := r.Header.Get("Content-Type")
  48. if contentType != "application/json" {
  49. klog.Errorf("contentType=%s, expect application/json", contentType)
  50. return
  51. }
  52. klog.V(2).Info(fmt.Sprintf("handling request: %s", body))
  53. // The AdmissionReview that was sent to the webhook
  54. requestedAdmissionReview := v1beta1.AdmissionReview{}
  55. // The AdmissionReview that will be returned
  56. responseAdmissionReview := v1beta1.AdmissionReview{}
  57. deserializer := codecs.UniversalDeserializer()
  58. if _, _, err := deserializer.Decode(body, nil, &requestedAdmissionReview); err != nil {
  59. klog.Error(err)
  60. responseAdmissionReview.Response = toAdmissionResponse(err)
  61. } else {
  62. // pass to admitFunc
  63. responseAdmissionReview.Response = admit(requestedAdmissionReview)
  64. }
  65. // Return the same UID
  66. responseAdmissionReview.Response.UID = requestedAdmissionReview.Request.UID
  67. klog.V(2).Info(fmt.Sprintf("sending response: %v", responseAdmissionReview.Response))
  68. respBytes, err := json.Marshal(responseAdmissionReview)
  69. if err != nil {
  70. klog.Error(err)
  71. }
  72. if _, err := w.Write(respBytes); err != nil {
  73. klog.Error(err)
  74. }
  75. }
  76. func serveAlwaysAllowDelayFiveSeconds(w http.ResponseWriter, r *http.Request) {
  77. serve(w, r, alwaysAllowDelayFiveSeconds)
  78. }
  79. func serveAlwaysDeny(w http.ResponseWriter, r *http.Request) {
  80. serve(w, r, alwaysDeny)
  81. }
  82. func serveAddLabel(w http.ResponseWriter, r *http.Request) {
  83. serve(w, r, addLabel)
  84. }
  85. func servePods(w http.ResponseWriter, r *http.Request) {
  86. serve(w, r, admitPods)
  87. }
  88. func serveAttachingPods(w http.ResponseWriter, r *http.Request) {
  89. serve(w, r, denySpecificAttachment)
  90. }
  91. func serveMutatePods(w http.ResponseWriter, r *http.Request) {
  92. serve(w, r, mutatePods)
  93. }
  94. func serveConfigmaps(w http.ResponseWriter, r *http.Request) {
  95. serve(w, r, admitConfigMaps)
  96. }
  97. func serveMutateConfigmaps(w http.ResponseWriter, r *http.Request) {
  98. serve(w, r, mutateConfigmaps)
  99. }
  100. func serveCustomResource(w http.ResponseWriter, r *http.Request) {
  101. serve(w, r, admitCustomResource)
  102. }
  103. func serveMutateCustomResource(w http.ResponseWriter, r *http.Request) {
  104. serve(w, r, mutateCustomResource)
  105. }
  106. func serveCRD(w http.ResponseWriter, r *http.Request) {
  107. serve(w, r, admitCRD)
  108. }
  109. func main() {
  110. klog.InitFlags(nil)
  111. var config Config
  112. config.addFlags()
  113. flag.Parse()
  114. http.HandleFunc("/always-allow-delay-5s", serveAlwaysAllowDelayFiveSeconds)
  115. http.HandleFunc("/always-deny", serveAlwaysDeny)
  116. http.HandleFunc("/add-label", serveAddLabel)
  117. http.HandleFunc("/pods", servePods)
  118. http.HandleFunc("/pods/attach", serveAttachingPods)
  119. http.HandleFunc("/mutating-pods", serveMutatePods)
  120. http.HandleFunc("/configmaps", serveConfigmaps)
  121. http.HandleFunc("/mutating-configmaps", serveMutateConfigmaps)
  122. http.HandleFunc("/custom-resource", serveCustomResource)
  123. http.HandleFunc("/mutating-custom-resource", serveMutateCustomResource)
  124. http.HandleFunc("/crd", serveCRD)
  125. server := &http.Server{
  126. Addr: ":443",
  127. TLSConfig: configTLS(config),
  128. }
  129. server.ListenAndServeTLS("", "")
  130. }