diff --git a/go.mod b/go.mod index 55a66211..dcc9fc43 100644 --- a/go.mod +++ b/go.mod @@ -66,7 +66,6 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20220327082430-c57b701bfc08 // indirect github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index 02e6ebea..31686711 100644 --- a/go.sum +++ b/go.sum @@ -172,8 +172,6 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -361,7 +359,6 @@ github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/V github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= diff --git a/vendor/github.com/coreos/go-systemd/v22/LICENSE b/vendor/github.com/coreos/go-systemd/v22/LICENSE deleted file mode 100644 index 37ec93a1..00000000 --- a/vendor/github.com/coreos/go-systemd/v22/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/github.com/coreos/go-systemd/v22/NOTICE b/vendor/github.com/coreos/go-systemd/v22/NOTICE deleted file mode 100644 index 23a0ada2..00000000 --- a/vendor/github.com/coreos/go-systemd/v22/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -CoreOS Project -Copyright 2018 CoreOS, Inc - -This product includes software developed at CoreOS, Inc. -(http://www.coreos.com/). diff --git a/vendor/github.com/coreos/go-systemd/v22/unit/deserialize.go b/vendor/github.com/coreos/go-systemd/v22/unit/deserialize.go deleted file mode 100644 index 283c1507..00000000 --- a/vendor/github.com/coreos/go-systemd/v22/unit/deserialize.go +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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 unit - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "io" - "strings" - "unicode" -) - -const ( - // SYSTEMD_LINE_MAX mimics the maximum line length that systemd can use. - // On typical systemd platforms (i.e. modern Linux), this will most - // commonly be 2048, so let's use that as a sanity check. - // Technically, we should probably pull this at runtime: - // SYSTEMD_LINE_MAX = int(C.sysconf(C.__SC_LINE_MAX)) - // but this would introduce an (unfortunate) dependency on cgo - SYSTEMD_LINE_MAX = 2048 - - // SYSTEMD_NEWLINE defines characters that systemd considers indicators - // for a newline. - SYSTEMD_NEWLINE = "\r\n" -) - -var ( - // ErrLineTooLong gets returned when a line is too long for systemd to handle. - ErrLineTooLong = fmt.Errorf("line too long (max %d bytes)", SYSTEMD_LINE_MAX) -) - -// DeserializeOptions parses a systemd unit file into a list of UnitOptions -func DeserializeOptions(f io.Reader) (opts []*UnitOption, err error) { - _, options, err := deserializeAll(f) - return options, err -} - -// DeserializeSections deserializes into a list of UnitSections. -func DeserializeSections(f io.Reader) ([]*UnitSection, error) { - sections, _, err := deserializeAll(f) - return sections, err -} - -// Deserialize parses a systemd unit file into a list of UnitOptions. -// Note: this function is deprecated in favor of DeserializeOptions -// and will be removed at a future date. -func Deserialize(f io.Reader) (opts []*UnitOption, err error) { - return DeserializeOptions(f) -} - -type lexDataType int - -const ( - sectionKind lexDataType = iota - optionKind -) - -// lexChanData - support either datatype in the lex channel. -// Poor man's union data type. -type lexData struct { - Type lexDataType - Option *UnitOption - Section *UnitSection -} - -// deserializeAll deserializes into UnitSections and UnitOptions. -func deserializeAll(f io.Reader) ([]*UnitSection, []*UnitOption, error) { - - lexer, lexchan, errchan := newLexer(f) - - go lexer.lex() - - sections := []*UnitSection{} - options := []*UnitOption{} - - for ld := range lexchan { - switch ld.Type { - case optionKind: - if ld.Option != nil { - // add to options - opt := ld.Option - options = append(options, &(*opt)) - - // sanity check. "should not happen" as sectionKind is first in code flow. - if len(sections) == 0 { - return nil, nil, fmt.Errorf( - "Unit file misparse: option before section") - } - - // add to newest section entries. - s := len(sections) - 1 - sections[s].Entries = append(sections[s].Entries, - &UnitEntry{Name: opt.Name, Value: opt.Value}) - } - case sectionKind: - if ld.Section != nil { - sections = append(sections, ld.Section) - } - } - } - - err := <-errchan - - return sections, options, err -} - -func newLexer(f io.Reader) (*lexer, <-chan *lexData, <-chan error) { - lexchan := make(chan *lexData) - errchan := make(chan error, 1) - buf := bufio.NewReader(f) - - return &lexer{buf, lexchan, errchan, ""}, lexchan, errchan -} - -type lexer struct { - buf *bufio.Reader - lexchan chan *lexData - errchan chan error - section string -} - -func (l *lexer) lex() { - defer func() { - close(l.lexchan) - close(l.errchan) - }() - next := l.lexNextSection - for next != nil { - if l.buf.Buffered() >= SYSTEMD_LINE_MAX { - // systemd truncates lines longer than LINE_MAX - // https://bugs.freedesktop.org/show_bug.cgi?id=85308 - // Rather than allowing this to pass silently, let's - // explicitly gate people from encountering this - line, err := l.buf.Peek(SYSTEMD_LINE_MAX) - if err != nil { - l.errchan <- err - return - } - if !bytes.ContainsAny(line, SYSTEMD_NEWLINE) { - l.errchan <- ErrLineTooLong - return - } - } - - var err error - next, err = next() - if err != nil { - l.errchan <- err - return - } - } -} - -type lexStep func() (lexStep, error) - -func (l *lexer) lexSectionName() (lexStep, error) { - sec, err := l.buf.ReadBytes(']') - if err != nil { - return nil, errors.New("unable to find end of section") - } - - return l.lexSectionSuffixFunc(string(sec[:len(sec)-1])), nil -} - -func (l *lexer) lexSectionSuffixFunc(section string) lexStep { - return func() (lexStep, error) { - garbage, _, err := l.toEOL() - if err != nil { - return nil, err - } - - garbage = bytes.TrimSpace(garbage) - if len(garbage) > 0 { - return nil, fmt.Errorf("found garbage after section name %s: %q", l.section, garbage) - } - - l.lexchan <- &lexData{ - Type: sectionKind, - Section: &UnitSection{Section: section, Entries: []*UnitEntry{}}, - Option: nil, - } - - return l.lexNextSectionOrOptionFunc(section), nil - } -} - -func (l *lexer) ignoreLineFunc(next lexStep) lexStep { - return func() (lexStep, error) { - for { - line, _, err := l.toEOL() - if err != nil { - return nil, err - } - - line = bytes.TrimSuffix(line, []byte{' '}) - - // lack of continuation means this line has been exhausted - if !bytes.HasSuffix(line, []byte{'\\'}) { - break - } - } - - // reached end of buffer, safe to exit - return next, nil - } -} - -func (l *lexer) lexNextSection() (lexStep, error) { - r, _, err := l.buf.ReadRune() - if err != nil { - if err == io.EOF { - err = nil - } - return nil, err - } - - if r == '[' { - return l.lexSectionName, nil - } else if isComment(r) { - return l.ignoreLineFunc(l.lexNextSection), nil - } - - return l.lexNextSection, nil -} - -func (l *lexer) lexNextSectionOrOptionFunc(section string) lexStep { - return func() (lexStep, error) { - r, _, err := l.buf.ReadRune() - if err != nil { - if err == io.EOF { - err = nil - } - return nil, err - } - - if unicode.IsSpace(r) { - return l.lexNextSectionOrOptionFunc(section), nil - } else if r == '[' { - return l.lexSectionName, nil - } else if isComment(r) { - return l.ignoreLineFunc(l.lexNextSectionOrOptionFunc(section)), nil - } - - l.buf.UnreadRune() - return l.lexOptionNameFunc(section), nil - } -} - -func (l *lexer) lexOptionNameFunc(section string) lexStep { - return func() (lexStep, error) { - var partial bytes.Buffer - for { - r, _, err := l.buf.ReadRune() - if err != nil { - return nil, err - } - - if r == '\n' || r == '\r' { - return nil, errors.New("unexpected newline encountered while parsing option name") - } - - if r == '=' { - break - } - - partial.WriteRune(r) - } - - name := strings.TrimSpace(partial.String()) - return l.lexOptionValueFunc(section, name, bytes.Buffer{}), nil - } -} - -func (l *lexer) lexOptionValueFunc(section, name string, partial bytes.Buffer) lexStep { - return func() (lexStep, error) { - for { - line, eof, err := l.toEOL() - if err != nil { - return nil, err - } - - if len(bytes.TrimSpace(line)) == 0 { - break - } - - partial.Write(line) - - // lack of continuation means this value has been exhausted - idx := bytes.LastIndex(line, []byte{'\\'}) - if idx == -1 || idx != (len(line)-1) { - break - } - - if !eof { - partial.WriteRune('\n') - } - - return l.lexOptionValueFunc(section, name, partial), nil - } - - val := partial.String() - if strings.HasSuffix(val, "\n") { - // A newline was added to the end, so the file didn't end with a backslash. - // => Keep the newline - val = strings.TrimSpace(val) + "\n" - } else { - val = strings.TrimSpace(val) - } - l.lexchan <- &lexData{ - Type: optionKind, - Section: nil, - Option: &UnitOption{Section: section, Name: name, Value: val}, - } - - return l.lexNextSectionOrOptionFunc(section), nil - } -} - -// toEOL reads until the end-of-line or end-of-file. -// Returns (data, EOFfound, error) -func (l *lexer) toEOL() ([]byte, bool, error) { - line, err := l.buf.ReadBytes('\n') - // ignore EOF here since it's roughly equivalent to EOL - if err != nil && err != io.EOF { - return nil, false, err - } - - line = bytes.TrimSuffix(line, []byte{'\r'}) - line = bytes.TrimSuffix(line, []byte{'\n'}) - - return line, err == io.EOF, nil -} - -func isComment(r rune) bool { - return r == '#' || r == ';' -} diff --git a/vendor/github.com/coreos/go-systemd/v22/unit/escape.go b/vendor/github.com/coreos/go-systemd/v22/unit/escape.go deleted file mode 100644 index 63b11726..00000000 --- a/vendor/github.com/coreos/go-systemd/v22/unit/escape.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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. - -// Implements systemd-escape [--unescape] [--path] - -package unit - -import ( - "fmt" - "strconv" - "strings" -) - -const ( - allowed = `:_.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789` -) - -// If isPath is true: -// We remove redundant '/'s, the leading '/', and trailing '/'. -// If the result is empty, a '/' is inserted. -// -// We always: -// Replace the following characters with `\x%x`: -// Leading `.` -// `-`, `\`, and anything not in this set: `:-_.\[0-9a-zA-Z]` -// Replace '/' with '-'. -func escape(unescaped string, isPath bool) string { - e := []byte{} - inSlashes := false - start := true - for i := 0; i < len(unescaped); i++ { - c := unescaped[i] - if isPath { - if c == '/' { - inSlashes = true - continue - } else if inSlashes { - inSlashes = false - if !start { - e = append(e, '-') - } - } - } - - if c == '/' { - e = append(e, '-') - } else if start && c == '.' || strings.IndexByte(allowed, c) == -1 { - e = append(e, []byte(fmt.Sprintf(`\x%x`, c))...) - } else { - e = append(e, c) - } - start = false - } - if isPath && len(e) == 0 { - e = append(e, '-') - } - return string(e) -} - -// If isPath is true: -// We always return a string beginning with '/'. -// -// We always: -// Replace '-' with '/'. -// Replace `\x%x` with the value represented in hex. -func unescape(escaped string, isPath bool) string { - u := []byte{} - for i := 0; i < len(escaped); i++ { - c := escaped[i] - if c == '-' { - c = '/' - } else if c == '\\' && len(escaped)-i >= 4 && escaped[i+1] == 'x' { - n, err := strconv.ParseInt(escaped[i+2:i+4], 16, 8) - if err == nil { - c = byte(n) - i += 3 - } - } - u = append(u, c) - } - if isPath && (len(u) == 0 || u[0] != '/') { - u = append([]byte("/"), u...) - } - return string(u) -} - -// UnitNameEscape escapes a string as `systemd-escape` would -func UnitNameEscape(unescaped string) string { - return escape(unescaped, false) -} - -// UnitNameUnescape unescapes a string as `systemd-escape --unescape` would -func UnitNameUnescape(escaped string) string { - return unescape(escaped, false) -} - -// UnitNamePathEscape escapes a string as `systemd-escape --path` would -func UnitNamePathEscape(unescaped string) string { - return escape(unescaped, true) -} - -// UnitNamePathUnescape unescapes a string as `systemd-escape --path --unescape` would -func UnitNamePathUnescape(escaped string) string { - return unescape(escaped, true) -} diff --git a/vendor/github.com/coreos/go-systemd/v22/unit/option.go b/vendor/github.com/coreos/go-systemd/v22/unit/option.go deleted file mode 100644 index 98e1af5c..00000000 --- a/vendor/github.com/coreos/go-systemd/v22/unit/option.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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 unit - -import ( - "fmt" -) - -// UnitOption represents an option in a systemd unit file. -type UnitOption struct { - Section string - Name string - Value string -} - -// NewUnitOption returns a new UnitOption instance with pre-set values. -func NewUnitOption(section, name, value string) *UnitOption { - return &UnitOption{Section: section, Name: name, Value: value} -} - -func (uo *UnitOption) String() string { - return fmt.Sprintf("{Section: %q, Name: %q, Value: %q}", uo.Section, uo.Name, uo.Value) -} - -// Match compares two UnitOptions and returns true if they are identical. -func (uo *UnitOption) Match(other *UnitOption) bool { - return uo.Section == other.Section && - uo.Name == other.Name && - uo.Value == other.Value -} - -// AllMatch compares two slices of UnitOptions and returns true if they are -// identical. -func AllMatch(u1 []*UnitOption, u2 []*UnitOption) bool { - length := len(u1) - if length != len(u2) { - return false - } - - for i := 0; i < length; i++ { - if !u1[i].Match(u2[i]) { - return false - } - } - - return true -} diff --git a/vendor/github.com/coreos/go-systemd/v22/unit/section.go b/vendor/github.com/coreos/go-systemd/v22/unit/section.go deleted file mode 100644 index 217a183c..00000000 --- a/vendor/github.com/coreos/go-systemd/v22/unit/section.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2020 CoreOS, Inc. -// -// 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 unit - -// UnitEntry is a single line entry in a Unit file. -type UnitEntry struct { - Name string - Value string -} - -// UnitSection is a section in a Unit file. The section name -// and a list of entries in that section. -type UnitSection struct { - Section string - Entries []*UnitEntry -} - -// String implements the stringify interface for UnitEntry -func (u *UnitEntry) String() string { - return "{Name: " + u.Name + ", " + "Value: " + u.Value + "}" -} - -// String implements the stringify interface for UnitSection -func (s *UnitSection) String() string { - result := "{Section: " + s.Section - for _, e := range s.Entries { - result += e.String() - } - - result += "}" - return result -} diff --git a/vendor/github.com/coreos/go-systemd/v22/unit/serialize.go b/vendor/github.com/coreos/go-systemd/v22/unit/serialize.go deleted file mode 100644 index c1b79c02..00000000 --- a/vendor/github.com/coreos/go-systemd/v22/unit/serialize.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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 unit - -import ( - "bytes" - "io" -) - -// Serialize encodes all of the given UnitOption objects into a -// unit file. When serialized the options are sorted in their -// supplied order but grouped by section. -func Serialize(opts []*UnitOption) io.Reader { - var buf bytes.Buffer - - if len(opts) == 0 { - return &buf - } - - // Index of sections -> ordered options - idx := map[string][]*UnitOption{} - // Separately preserve order in which sections were seen - sections := []string{} - for _, opt := range opts { - sec := opt.Section - if _, ok := idx[sec]; !ok { - sections = append(sections, sec) - } - idx[sec] = append(idx[sec], opt) - } - - for i, sect := range sections { - writeSectionHeader(&buf, sect) - writeNewline(&buf) - - opts := idx[sect] - for _, opt := range opts { - writeOption(&buf, opt) - writeNewline(&buf) - } - if i < len(sections)-1 { - writeNewline(&buf) - } - } - - return &buf -} - -// SerializeSections will serializes the unit file from the given -// UnitSections. -func SerializeSections(sections []*UnitSection) io.Reader { - - var buf bytes.Buffer - - for i, s := range sections { - writeSectionHeader(&buf, s.Section) - writeNewline(&buf) - - for _, e := range s.Entries { - writeOption(&buf, &UnitOption{s.Section, e.Name, e.Value}) - writeNewline(&buf) - } - - if i < len(sections)-1 { - writeNewline(&buf) - } - } - - return &buf -} - -func writeNewline(buf *bytes.Buffer) { - buf.WriteRune('\n') -} - -func writeSectionHeader(buf *bytes.Buffer, section string) { - buf.WriteRune('[') - buf.WriteString(section) - buf.WriteRune(']') -} - -func writeOption(buf *bytes.Buffer, opt *UnitOption) { - buf.WriteString(opt.Name) - buf.WriteRune('=') - buf.WriteString(opt.Value) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/add.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/add.go deleted file mode 100644 index 7734a56e..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/add.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2022 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 certificates - -import ( - "context" - "fmt" - "sync/atomic" - "time" - - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - "k8s.io/utils/clock" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - - "github.com/gardener/gardener/extensions/pkg/webhook" -) - -// DefaultSyncPeriod is the default sync period for the certificate reconciler and reloader. -var DefaultSyncPeriod = 5 * time.Minute - -// AddCertificateManagementToManager adds reconcilers to the given manager that manage the webhook certificates, namely -// - generate and auto-rotate the webhook CA and server cert using a secrets manager (in leader only) -// - fetch current webhook server cert and write it to disk for the webhook server to pick up (in all replicas) -func AddCertificateManagementToManager( - ctx context.Context, - mgr manager.Manager, - clock clock.Clock, - sourceWebhookConfigs []client.Object, - shootWebhookConfig *admissionregistrationv1.MutatingWebhookConfiguration, - atomicShootWebhookConfig *atomic.Value, - shootNamespaceSelector map[string]string, - shootWebhookManagedResourceName string, - componentName string, - namespace string, - mode string, - url string, -) error { - var ( - identity = webhook.PrefixedName(componentName) + "-webhook" - caSecretName = "ca-" + componentName + "-webhook" - serverSecretName = componentName + "-webhook-server" - ) - - // first, add reconciler that manages the certificates and injects them into webhook configs - // (only running in the leader or once if no secrets have been generated yet) - if err := (&reconciler{ - Clock: clock, - SyncPeriod: DefaultSyncPeriod, - SourceWebhookConfigs: sourceWebhookConfigs, - ShootWebhookConfig: shootWebhookConfig, - AtomicShootWebhookConfig: atomicShootWebhookConfig, - CASecretName: caSecretName, - ServerSecretName: serverSecretName, - Namespace: namespace, - Identity: identity, - ComponentName: componentName, - ShootWebhookManagedResourceName: shootWebhookManagedResourceName, - ShootNamespaceSelector: shootNamespaceSelector, - Mode: mode, - URL: url, - }).AddToManager(ctx, mgr); err != nil { - return fmt.Errorf("failed to add webhook server certificate reconciler: %w", err) - } - - // secondly, add reloader that fetches the managed certificates and writes it to the webhook server's cert dir - // (running in all replicas) - if err := (&reloader{ - SyncPeriod: DefaultSyncPeriod, - ServerSecretName: serverSecretName, - Namespace: namespace, - Identity: identity, - }).AddToManager(ctx, mgr); err != nil { - return fmt.Errorf("failed to add webhook server certificate reloader: %w", err) - } - - return nil -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/certificates.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/certificates.go deleted file mode 100644 index 560fd35d..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/certificates.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2022 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 certificates - -import ( - "fmt" - "net" - "os" - "path/filepath" - "time" - - "k8s.io/utils/pointer" - - "github.com/gardener/gardener/extensions/pkg/webhook" - secretsutils "github.com/gardener/gardener/pkg/utils/secrets" -) - -// GenerateUnmanagedCertificates generates a one-off CA and server cert for a webhook server. The server certificate and -// key are written to certDir. This is useful for local development. -func GenerateUnmanagedCertificates(providerName, certDir, mode, url string) ([]byte, error) { - caConfig := getWebhookCAConfig(providerName) - // we want to use a long validity here, because we don't auto-renew certificates - caConfig.Validity = pointer.Duration(10 * 365 * 24 * time.Hour) // 10y - - caCert, err := caConfig.GenerateCertificate() - if err != nil { - return nil, err - } - - serverConfig := getWebhookServerCertConfig(providerName, "", providerName, mode, url) - serverConfig.SigningCA = caCert - - serverCert, err := serverConfig.GenerateCertificate() - if err != nil { - return nil, err - } - - return caCert.CertificatePEM, writeCertificatesToDisk(certDir, serverCert.CertificatePEM, serverCert.PrivateKeyPEM) -} - -var caCertificateValidity = 30 * 24 * time.Hour // 30d - -func getWebhookCAConfig(name string) *secretsutils.CertificateSecretConfig { - return &secretsutils.CertificateSecretConfig{ - Name: name, - CommonName: name, - CertType: secretsutils.CACert, - Validity: &caCertificateValidity, - } -} - -func getWebhookServerCertConfig(name, namespace, componentName, mode, url string) *secretsutils.CertificateSecretConfig { - var ( - dnsNames []string - ipAddresses []net.IP - - serverName = url - ) - - if host, _, err := net.SplitHostPort(url); err == nil { - serverName = host - } - - switch mode { - case webhook.ModeURL: - if addr := net.ParseIP(serverName); addr != nil { - ipAddresses = []net.IP{addr} - } else { - dnsNames = []string{serverName} - } - - case webhook.ModeService: - dnsNames = []string{webhook.PrefixedName(componentName)} - if namespace != "" { - dnsNames = append(dnsNames, - fmt.Sprintf("%s.%s", webhook.PrefixedName(componentName), namespace), - fmt.Sprintf("%s.%s.svc", webhook.PrefixedName(componentName), namespace), - ) - } - } - - return &secretsutils.CertificateSecretConfig{ - Name: name, - CommonName: componentName, - DNSNames: dnsNames, - IPAddresses: ipAddresses, - CertType: secretsutils.ServerCert, - SkipPublishingCACertificate: true, - } -} - -func writeCertificatesToDisk(certDir string, serverCert, serverKey []byte) error { - var ( - serverKeyPath = filepath.Join(certDir, secretsutils.DataKeyPrivateKey) - serverCertPath = filepath.Join(certDir, secretsutils.DataKeyCertificate) - ) - - if err := os.MkdirAll(certDir, 0755); err != nil { - return err - } - if err := os.WriteFile(serverKeyPath, serverKey, 0666); err != nil { - return err - } - return os.WriteFile(serverCertPath, serverCert, 0666) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reconciler.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reconciler.go deleted file mode 100644 index c9d79b89..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reconciler.go +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2022 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 certificates - -import ( - "context" - "fmt" - "sync/atomic" - "time" - - "github.com/go-logr/logr" - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/client-go/util/workqueue" - "k8s.io/utils/clock" - "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/gardener/gardener/extensions/pkg/webhook" - extensionsshootwebhook "github.com/gardener/gardener/extensions/pkg/webhook/shoot" - "github.com/gardener/gardener/pkg/controllerutils" - kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" - secretsutils "github.com/gardener/gardener/pkg/utils/secrets" - secretsmanager "github.com/gardener/gardener/pkg/utils/secrets/manager" -) - -const certificateReconcilerName = "webhook-certificate" - -// reconciler is a simple reconciler that manages the webhook CA and server certificate using a secrets manager. -// It runs Generate for both secret configs followed by Cleanup every SyncPeriod and updates the WebhookConfigurations -// accordingly with the new CA bundle. -type reconciler struct { - // Clock is the clock. - Clock clock.Clock - // SyncPeriod is the frequency with which to reload the server cert. Defaults to 5m. - SyncPeriod time.Duration - // SourceWebhookConfigs are the webhook configurations to reconcile in the Source cluster. - SourceWebhookConfigs []client.Object - // ShootWebhookConfig is the webhook configuration to reconcile in all Shoot clusters. - ShootWebhookConfig *admissionregistrationv1.MutatingWebhookConfiguration - // AtomicShootWebhookConfig is an atomic value in which this reconciler will store the updated ShootWebhookConfig. - // It is supposed to be shared with the ControlPlane actuator. I.e. if the CA bundle changes, this reconciler - // updates the CA bundle in this value so that the ControlPlane actuator can configure the correct (the new) CA - // bundle for newly created shoots by loading this value. - AtomicShootWebhookConfig *atomic.Value - // CASecretName is the CA config name. - CASecretName string - // ServerSecretName is the server certificate config name. - ServerSecretName string - // Namespace where the server certificate secret should be located in. - Namespace string - // Identity of the secrets manager used for managing the secret. - Identity string - // Name of the component. - ComponentName string - // ShootWebhookManagedResourceName is the name of the ManagedResource containing the raw shoot webhook config. - ShootWebhookManagedResourceName string - // ShootNamespaceSelector is a label selector for shoot namespaces relevant to the extension. - ShootNamespaceSelector map[string]string - // Mode is the webhook client config mode. - Mode string - // URL is the URL that is used to register the webhooks in Kubernetes. - URL string - - serverPort int - client client.Client -} - -// AddToManager generates webhook CA and server cert if it doesn't exist on the cluster yet. Then it adds reconciler to -// the given manager in order to periodically regenerate the webhook secrets. -func (r *reconciler) AddToManager(ctx context.Context, mgr manager.Manager) error { - r.serverPort = mgr.GetWebhookServer().Port - r.client = mgr.GetClient() - - present, err := isWebhookServerSecretPresent(ctx, mgr.GetAPIReader(), r.ServerSecretName, r.Namespace, r.Identity) - if err != nil { - return err - } - - // if webhook CA and server cert have not been generated yet, we need to generate them for the first time now, - // otherwise the webhook server will not be able to start (which is a non-leader election runnable and is therefore - // started before this controller) - if !present { - // cache is not started yet, we need an uncached client for the initial setup - uncachedClient, err := client.NewDelegatingClient(client.NewDelegatingClientInput{ - Client: r.client, - CacheReader: mgr.GetAPIReader(), - }) - if err != nil { - return fmt.Errorf("failed to create new unchached client: %w", err) - } - - sm, err := r.newSecretsManager(ctx, mgr.GetLogger(), uncachedClient) - if err != nil { - return fmt.Errorf("failed to create new SecretsManager: %w", err) - } - - if _, err = r.generateWebhookCA(ctx, sm); err != nil { - return err - } - - if _, err = r.generateWebhookServerCert(ctx, sm); err != nil { - return err - } - } - - // add controller, that regenerates the CA and server cert secrets periodically - ctrl, err := controller.New(certificateReconcilerName, mgr, controller.Options{ - Reconciler: r, - RecoverPanic: pointer.Bool(true), - // if going into exponential backoff, wait at most the configured sync period - RateLimiter: workqueue.NewWithMaxWaitRateLimiter(workqueue.DefaultControllerRateLimiter(), r.SyncPeriod), - }) - if err != nil { - return err - } - - return ctrl.Watch(controllerutils.EnqueueOnce, nil) -} - -// Reconcile generates new certificates if needed and updates all webhook configurations. -func (r *reconciler) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile.Result, error) { - log := logf.FromContext(ctx) - - sm, err := r.newSecretsManager(ctx, log, r.client) - if err != nil { - return reconcile.Result{}, fmt.Errorf("failed to create new SecretsManager: %w", err) - } - - caSecret, err := r.generateWebhookCA(ctx, sm) - if err != nil { - return reconcile.Result{}, err - } - caBundleSecret, found := sm.Get(r.CASecretName) - if !found { - return reconcile.Result{}, fmt.Errorf("secret %q not found", r.CASecretName) - } - - log = log.WithValues( - "secretNamespace", r.Namespace, - "identity", r.Identity, - "caSecretName", caSecret.Name, - "caBundleSecretName", caBundleSecret.Name, - ) - log.Info("Generated webhook CA") - - serverSecret, err := r.generateWebhookServerCert(ctx, sm) - if err != nil { - return reconcile.Result{}, err - } - log.Info("Generated webhook server cert", "serverSecretName", serverSecret.Name) - - for _, sourceWebhookConfig := range r.SourceWebhookConfigs { - if sourceWebhookConfig == nil { - continue - } - if err := r.reconcileSourceWebhookConfig(ctx, sourceWebhookConfig, caBundleSecret); err != nil { - return reconcile.Result{}, fmt.Errorf("error reconciling source webhook config %s: %w", client.ObjectKeyFromObject(sourceWebhookConfig), err) - } - log.Info("Updated source webhook config with new CA bundle", "webhookConfig", sourceWebhookConfig) - } - - if r.ShootWebhookConfig != nil { - // update shoot webhook config object (in memory) with the freshly created CA bundle which is also used by the - // ControlPlane actuator - if err := webhook.InjectCABundleIntoWebhookConfig(r.ShootWebhookConfig, caBundleSecret.Data[secretsutils.DataKeyCertificateBundle]); err != nil { - return reconcile.Result{}, err - } - r.AtomicShootWebhookConfig.Store(r.ShootWebhookConfig.DeepCopy()) - - // reconcile all shoot webhook configs with the freshly created CA bundle - if err := extensionsshootwebhook.ReconcileWebhooksForAllNamespaces(ctx, r.client, r.Namespace, r.ComponentName, r.ShootWebhookManagedResourceName, r.ShootNamespaceSelector, r.serverPort, r.ShootWebhookConfig); err != nil { - return reconcile.Result{}, fmt.Errorf("error reconciling all shoot webhook configs: %w", err) - } - log.Info("Updated all shoot webhook configs with new CA bundle", "webhookConfig", r.ShootWebhookConfig) - } - - if err := sm.Cleanup(ctx); err != nil { - return reconcile.Result{}, err - } - - return reconcile.Result{RequeueAfter: r.SyncPeriod}, nil -} - -func (r *reconciler) reconcileSourceWebhookConfig(ctx context.Context, sourceWebhookConfig client.Object, caBundleSecret *corev1.Secret) error { - // copy object so that we don't lose its name on API/client errors - config := sourceWebhookConfig.DeepCopyObject().(client.Object) - if err := r.client.Get(ctx, client.ObjectKeyFromObject(config), config); err != nil { - return err - } - - patch := client.MergeFromWithOptions(config.DeepCopyObject().(client.Object), client.MergeFromWithOptimisticLock{}) - if err := webhook.InjectCABundleIntoWebhookConfig(config, caBundleSecret.Data[secretsutils.DataKeyCertificateBundle]); err != nil { - return err - } - return r.client.Patch(ctx, config, patch) -} - -func isWebhookServerSecretPresent(ctx context.Context, c client.Reader, secretName, namespace, identity string) (bool, error) { - return kubernetesutils.ResourcesExist(ctx, c, corev1.SchemeGroupVersion.WithKind("SecretList"), client.InNamespace(namespace), client.MatchingLabels{ - secretsmanager.LabelKeyName: secretName, - secretsmanager.LabelKeyManagedBy: secretsmanager.LabelValueSecretsManager, - secretsmanager.LabelKeyManagerIdentity: identity, - }) -} - -func (r *reconciler) newSecretsManager(ctx context.Context, log logr.Logger, c client.Client) (secretsmanager.Interface, error) { - return secretsmanager.New( - ctx, - log.WithName("secretsmanager"), - r.Clock, - c, - r.Namespace, - r.Identity, - secretsmanager.Config{CASecretAutoRotation: true}, - ) -} - -func (r *reconciler) generateWebhookCA(ctx context.Context, sm secretsmanager.Interface) (*corev1.Secret, error) { - return sm.Generate(ctx, getWebhookCAConfig(r.CASecretName), - secretsmanager.Rotate(secretsmanager.KeepOld), secretsmanager.IgnoreOldSecretsAfter(24*time.Hour)) -} - -func (r *reconciler) generateWebhookServerCert(ctx context.Context, sm secretsmanager.Interface) (*corev1.Secret, error) { - // use current CA for signing server cert to prevent mismatches when dropping the old CA from the webhook config - return sm.Generate(ctx, getWebhookServerCertConfig(r.ServerSecretName, r.Namespace, r.ComponentName, r.Mode, r.URL), - secretsmanager.SignedByCA(r.CASecretName, secretsmanager.UseCurrentCA)) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reloader.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reloader.go deleted file mode 100644 index 826ab89d..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reloader.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2022 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 certificates - -import ( - "context" - "fmt" - "sync" - "time" - - corev1 "k8s.io/api/core/v1" - "k8s.io/client-go/util/workqueue" - "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/gardener/gardener/pkg/controllerutils" - secretsutils "github.com/gardener/gardener/pkg/utils/secrets" - secretsmanager "github.com/gardener/gardener/pkg/utils/secrets/manager" -) - -const certificateReloaderName = "webhook-certificate-reloader" - -// reloader is a simple reconciler that retrieves the current webhook server certificate managed by a secrets manager -// every syncPeriod and writes it to certDir. -type reloader struct { - // SyncPeriod is the frequency with which to reload the server cert. Defaults to 5m. - SyncPeriod time.Duration - // ServerSecretName is the server certificate config name. - ServerSecretName string - // Namespace where the server certificate secret is located in. - Namespace string - // Identity of the secrets manager used for managing the secret. - Identity string - - lock sync.Mutex - reader client.Reader - certDir string - newestServerSecretName string -} - -// AddToManager does an initial retrieval of an existing webhook server secret and then adds reloader to the given -// manager in order to periodically reload the secret from the cluster. -func (r *reloader) AddToManager(ctx context.Context, mgr manager.Manager) error { - r.reader = mgr.GetClient() - r.certDir = mgr.GetWebhookServer().CertDir - - // initial retrieval of server cert, needed in order for the webhook server to start successfully - found, _, serverCert, serverKey, err := r.getServerCert(ctx, mgr.GetAPIReader()) - if err != nil { - return err - } - - if !found { - // if we can't find a server cert secret on startup, the leader has not yet generated one - // exit and retry on next restart - return fmt.Errorf("couldn't find webhook server secret with name %q managed by secrets manager %q in namespace %q", r.ServerSecretName, r.Identity, r.Namespace) - } - - if err = writeCertificatesToDisk(r.certDir, serverCert, serverKey); err != nil { - return err - } - - // add controller that reloads the server cert secret periodically - ctrl, err := controller.NewUnmanaged(certificateReloaderName, mgr, controller.Options{ - Reconciler: r, - RecoverPanic: pointer.Bool(true), - // if going into exponential backoff, wait at most the configured sync period - RateLimiter: workqueue.NewWithMaxWaitRateLimiter(workqueue.DefaultControllerRateLimiter(), r.SyncPeriod), - }) - if err != nil { - return err - } - - if err = ctrl.Watch(controllerutils.EnqueueOnce, nil); err != nil { - return err - } - - // we need to run this controller in all replicas even if they aren't leader right now, so that webhook servers - // in stand-by replicas reload rotated server certificates as well - return mgr.Add(nonLeaderElectionRunnable{ctrl}) -} - -// Reconcile reloads the server certificates from the cluster and writes them to the cert directory if they have -// changed. From here, the controller-runtime's certwatcher will pick them up and use them for the webhook server. -func (r *reloader) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile.Result, error) { - log := logf.FromContext(ctx).WithValues( - "secretConfigName", r.ServerSecretName, - "secretNamespace", r.Namespace, - "identity", r.Identity, - "certDir", r.certDir, - ) - - log.V(1).Info("Reloading server certificate from secret") - - found, secretName, serverCert, serverKey, err := r.getServerCert(ctx, r.reader) - if err != nil { - return reconcile.Result{}, fmt.Errorf("error retrieving secret %q from namespace %q", r.ServerSecretName, r.Namespace) - } - - if !found { - log.Info("Couldn't find webhook server secret, retrying") - return reconcile.Result{Requeue: true}, nil - } - - log = log.WithValues("secretName", secretName) - - r.lock.Lock() - defer r.lock.Unlock() - - // prevent unnecessary disk writes - if secretName == r.newestServerSecretName { - log.V(1).Info("Secret already written to disk, checking again later") - return reconcile.Result{RequeueAfter: r.SyncPeriod}, nil - } - - log.Info("Found new secret, writing certificate to disk") - if err = writeCertificatesToDisk(r.certDir, serverCert, serverKey); err != nil { - return reconcile.Result{}, err - } - - r.newestServerSecretName = secretName - return reconcile.Result{RequeueAfter: r.SyncPeriod}, nil -} - -func (r *reloader) getServerCert(ctx context.Context, reader client.Reader) (bool, string, []byte, []byte, error) { - secretList := &corev1.SecretList{} - if err := reader.List(ctx, secretList, client.InNamespace(r.Namespace), client.MatchingLabels{ - secretsmanager.LabelKeyName: r.ServerSecretName, - secretsmanager.LabelKeyManagedBy: secretsmanager.LabelValueSecretsManager, - secretsmanager.LabelKeyManagerIdentity: r.Identity, - }); err != nil { - return false, "", nil, nil, err - } - - if len(secretList.Items) != 1 { - return false, "", nil, nil, nil - } - - s := secretList.Items[0] - return true, s.Name, s.Data[secretsutils.DataKeyCertificate], s.Data[secretsutils.DataKeyPrivateKey], nil -} - -type nonLeaderElectionRunnable struct { - manager.Runnable -} - -func (n nonLeaderElectionRunnable) NeedLeaderElection() bool { - return false -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/handler.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/handler.go deleted file mode 100644 index 7de38bc5..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/handler.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 webhook - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/api/equality" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/serializer" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/runtime/inject" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - predicateutils "github.com/gardener/gardener/pkg/controllerutils/predicate" -) - -// HandlerBuilder contains information which are required to create an admission handler. -type HandlerBuilder struct { - mutatorMap map[Mutator][]Type - predicates []predicate.Predicate - scheme *runtime.Scheme - logger logr.Logger -} - -// NewBuilder creates a new HandlerBuilder. -func NewBuilder(mgr manager.Manager, logger logr.Logger) *HandlerBuilder { - return &HandlerBuilder{ - mutatorMap: make(map[Mutator][]Type), - scheme: mgr.GetScheme(), - logger: logger.WithName("handler"), - } -} - -// WithMutator adds the given mutator for the given types to the HandlerBuilder. -func (b *HandlerBuilder) WithMutator(mutator Mutator, types ...Type) *HandlerBuilder { - mutator = hybridMutator(mutator) - b.mutatorMap[mutator] = append(b.mutatorMap[mutator], types...) - - return b -} - -// WithValidator adds the given validator for the given types to the HandlerBuilder. -func (b *HandlerBuilder) WithValidator(validator Validator, types ...Type) *HandlerBuilder { - mutator := hybridValidator(validator) - b.mutatorMap[mutator] = append(b.mutatorMap[mutator], types...) - return b -} - -// WithPredicates adds the given predicates to the HandlerBuilder. -func (b *HandlerBuilder) WithPredicates(predicates ...predicate.Predicate) *HandlerBuilder { - b.predicates = append(b.predicates, predicates...) - return b -} - -// Build creates a new admission.Handler with the settings previously specified with the HandlerBuilder's functions. -func (b *HandlerBuilder) Build() (admission.Handler, error) { - h := &handler{ - typesMap: make(map[metav1.GroupVersionKind]client.Object), - mutatorMap: make(map[metav1.GroupVersionKind]Mutator), - predicates: b.predicates, - scheme: b.scheme, - logger: b.logger, - } - - for m, t := range b.mutatorMap { - typesMap, err := buildTypesMap(b.scheme, objectsFromTypes(t)) - if err != nil { - return nil, err - } - mutator := m - for gvk, obj := range typesMap { - h.typesMap[gvk] = obj - h.mutatorMap[gvk] = mutator - } - } - h.decoder = serializer.NewCodecFactory(b.scheme).UniversalDecoder() - - return h, nil -} - -type handler struct { - typesMap map[metav1.GroupVersionKind]client.Object - mutatorMap map[metav1.GroupVersionKind]Mutator - predicates []predicate.Predicate - decoder runtime.Decoder - scheme *runtime.Scheme - logger logr.Logger -} - -// InjectFunc calls the inject.Func on the handler mutators. -func (h *handler) InjectFunc(f inject.Func) error { - for _, mutator := range h.mutatorMap { - if err := f(mutator); err != nil { - return fmt.Errorf("could not inject into the mutator: %w", err) - } - } - return nil -} - -// Handle handles the given admission request. -func (h *handler) Handle(ctx context.Context, req admission.Request) admission.Response { - ar := req.AdmissionRequest - - // Decode object - t, ok := h.typesMap[ar.Kind] - if !ok { - // check if we can find an internal type - for gvk, obj := range h.typesMap { - if gvk.Version == runtime.APIVersionInternal && gvk.Group == ar.Kind.Group && gvk.Kind == ar.Kind.Kind { - t = obj - break - } - } - if t == nil { - return admission.Errored(http.StatusBadRequest, fmt.Errorf("unexpected request kind %s", ar.Kind.String())) - } - } - - mutator, ok := h.mutatorMap[ar.Kind] - if !ok { - // check if we can find an internal type - for gvk, m := range h.mutatorMap { - if gvk.Version == runtime.APIVersionInternal && gvk.Group == ar.Kind.Group && gvk.Kind == ar.Kind.Kind { - mutator = m - break - } - } - if mutator == nil { - return admission.Errored(http.StatusBadRequest, fmt.Errorf("unexpected request kind %s", ar.Kind.String())) - } - } - - return handle(ctx, req, mutator, t, h.decoder, h.logger, h.predicates...) -} - -func handle(ctx context.Context, req admission.Request, m Mutator, t client.Object, decoder runtime.Decoder, logger logr.Logger, predicates ...predicate.Predicate) admission.Response { - ar := req.AdmissionRequest - - // Decode object - obj := t.DeepCopyObject().(client.Object) - _, _, err := decoder.Decode(req.Object.Raw, nil, obj) - if err != nil { - logger.Error(err, "Could not decode request", "request", ar) - return admission.Errored(http.StatusBadRequest, fmt.Errorf("could not decode request %v: %w", ar, err)) - } - - var oldObj client.Object - - // Only UPDATE and DELETE operations have oldObjects. - if len(req.OldObject.Raw) != 0 { - oldObj = t.DeepCopyObject().(client.Object) - if _, _, err := decoder.Decode(ar.OldObject.Raw, nil, oldObj); err != nil { - logger.Error(err, "Could not decode old object", "object", oldObj) - return admission.Errored(http.StatusBadRequest, fmt.Errorf("could not decode old object %v: %v", oldObj, err)) - } - } - - // Run object through predicates - if !predicateutils.EvalGeneric(obj, predicates...) { - return admission.ValidationResponse(true, "") - } - - // Process the resource - newObj := obj.DeepCopyObject().(client.Object) - if err = m.Mutate(ctx, newObj, oldObj); err != nil { - logger.Error(fmt.Errorf("could not process: %w", err), "Admission denied", "kind", ar.Kind.Kind, "namespace", obj.GetNamespace(), "name", obj.GetName()) - return admission.Errored(http.StatusUnprocessableEntity, err) - } - - _, isValidator := m.(Validator) - // Return a patch response if the resource should be changed - if !isValidator && !equality.Semantic.DeepEqual(obj, newObj) { - oldObjMarshaled, err := json.Marshal(obj) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - newObjMarshaled, err := json.Marshal(newObj) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - - return admission.PatchResponseFromRaw(oldObjMarshaled, newObjMarshaled) - } - - // Return a validation response if the resource should not be changed - return admission.ValidationResponse(true, "") -} - -func objectsFromTypes(in []Type) []client.Object { - out := make([]client.Object, 0, len(in)) - for _, t := range in { - out = append(out, t.Obj) - } - return out -} - -// buildTypesMap builds a map of the given types keyed by their GroupVersionKind, using the scheme from the given Manager. -func buildTypesMap(scheme *runtime.Scheme, types []client.Object) (map[metav1.GroupVersionKind]client.Object, error) { - typesMap := make(map[metav1.GroupVersionKind]client.Object) - for _, t := range types { - // Get GVK from the type - gvk, err := apiutil.GVKForObject(t, scheme) - if err != nil { - return nil, fmt.Errorf("could not get GroupVersionKind from object %v: %w", t, err) - } - - // Add the type to the types map - typesMap[metav1.GroupVersionKind(gvk)] = t - } - return typesMap, nil -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/handler_shootclient.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/handler_shootclient.go deleted file mode 100644 index d1163c31..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/handler_shootclient.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 webhook - -import ( - "context" - "fmt" - "net/http" - "strings" - - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/serializer" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/runtime/inject" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - extensionsconfig "github.com/gardener/gardener/extensions/pkg/apis/config" - "github.com/gardener/gardener/extensions/pkg/util" - v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" -) - -// NewHandlerWithShootClient creates a new handler for the given types, using the given mutator, and logger. -func NewHandlerWithShootClient(mgr manager.Manager, types []Type, mutator MutatorWithShootClient, logger logr.Logger) (http.Handler, error) { - // Build a map of the given types keyed by their GVKs - typesMap, err := buildTypesMap(mgr.GetScheme(), objectsFromTypes(types)) - if err != nil { - return nil, err - } - - // inject RemoteAddr into admission http.Handler, we need it to identify which API server called the webhook server - // in order to create a client for that shoot cluster. - return remoteAddrInjectingHandler{ - Handler: &admission.Webhook{ - Handler: &handlerShootClient{ - typesMap: typesMap, - mutator: mutator, - logger: logger.WithName("handlerShootClient"), - }, - RecoverPanic: true, - }, - }, nil -} - -type handlerShootClient struct { - typesMap map[metav1.GroupVersionKind]client.Object - mutator MutatorWithShootClient - client client.Client - decoder runtime.Decoder - logger logr.Logger -} - -// InjectScheme injects the given scheme into the handler. -func (h *handlerShootClient) InjectScheme(s *runtime.Scheme) error { - h.decoder = serializer.NewCodecFactory(s).UniversalDecoder() - return nil -} - -// InjectFunc injects stuff into the mutator. -func (h *handlerShootClient) InjectFunc(f inject.Func) error { - return f(h.mutator) -} - -// InjectClient injects a client. -func (h *handlerShootClient) InjectClient(client client.Client) error { - h.client = client - return nil -} - -func (h *handlerShootClient) Handle(ctx context.Context, req admission.Request) admission.Response { - var mut MutateFunc = func(ctx context.Context, new, old client.Object) error { - // TODO: replace this logic with a proper authentication mechanism - // see https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers - // API servers should authenticate against webhooks servers using TLS client certs, from which the webhook - // can identify from which shoot cluster the webhook call is coming - remoteAddrValue := ctx.Value(remoteAddrContextKey) - if remoteAddrValue == nil { - return fmt.Errorf("didn't receive remote address") - } - - remoteAddr, ok := remoteAddrValue.(string) - if !ok { - return fmt.Errorf("remote address expected to be string, got %T", remoteAddrValue) - } - - ipPort := strings.Split(remoteAddr, ":") - if len(ipPort) < 1 { - return fmt.Errorf("remote address not parseable: %s", remoteAddr) - } - ip := ipPort[0] - - podList := &corev1.PodList{} - if err := h.client.List(ctx, podList, client.MatchingLabels{ - v1beta1constants.LabelApp: v1beta1constants.LabelKubernetes, - v1beta1constants.LabelRole: v1beta1constants.LabelAPIServer, - }); err != nil { - return fmt.Errorf("error while listing all pods: %w", err) - } - - var shootNamespace string - for _, pod := range podList.Items { - if pod.Status.PodIP == ip { - shootNamespace = pod.Namespace - break - } - } - - if len(shootNamespace) == 0 { - return fmt.Errorf("could not find shoot namespace for webhook request from remote address %s", remoteAddr) - } - - _, shootClient, err := util.NewClientForShoot(ctx, h.client, shootNamespace, client.Options{}, extensionsconfig.RESTOptions{}) - if err != nil { - return fmt.Errorf("could not create shoot client: %w", err) - } - - return h.mutator.Mutate(ctx, new, old, shootClient) - } - - // Decode object - t, ok := h.typesMap[req.AdmissionRequest.Kind] - if !ok { - return admission.Errored(http.StatusBadRequest, fmt.Errorf("unexpected request kind %s", req.AdmissionRequest.Kind)) - } - - return handle(ctx, req, mut, t, h.decoder, h.logger) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/mutator.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/mutator.go deleted file mode 100644 index a1d9973e..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/mutator.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 webhook - -import ( - "context" - "fmt" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/runtime/inject" -) - -// Mutator validates and if needed mutates objects. -type Mutator interface { - // Mutate validates and if needed mutates the given object. - // "old" is optional and it must always be checked for nil. - Mutate(ctx context.Context, new, old client.Object) error -} - -// MutatorWithShootClient validates and if needed mutates objects. It needs the shoot client. -type MutatorWithShootClient interface { - // Mutate validates and if needed mutates the given object. - // "old" is optional and it must always be checked for nil. - Mutate(ctx context.Context, new, old client.Object, shootClient client.Client) error -} -type mutatorWrapper struct { - Mutator -} - -// InjectFunc calls the inject.Func on the handler mutators. -func (d *mutatorWrapper) InjectFunc(f inject.Func) error { - if err := f(d.Mutator); err != nil { - return fmt.Errorf("could not inject into the mutator: %w", err) - } - return nil -} - -func hybridMutator(mut Mutator) Mutator { - return &mutatorWrapper{mut} -} - -// MutateFunc is a func to be used directly as an implementation for Mutator -type MutateFunc func(ctx context.Context, new, old client.Object) error - -// Mutate validates and if needed mutates the given object. -func (mf MutateFunc) Mutate(ctx context.Context, new, old client.Object) error { - return mf(ctx, new, old) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/registration.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/registration.go deleted file mode 100644 index db174e6d..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/registration.go +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 webhook - -import ( - "context" - "fmt" - "strings" - - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" - - v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" - "github.com/gardener/gardener/pkg/controllerutils" - "github.com/gardener/gardener/pkg/utils/kubernetes" -) - -const ( - // NamePrefix is the prefix used for {Valida,Muta}tingWebhookConfigurations of extensions. - NamePrefix = "gardener-extension-" - // NameSuffixShoot is the suffix used for {Valida,Muta}tingWebhookConfigurations of extensions targeting a shoot. - NameSuffixShoot = "-shoot" - // ModeService is a constant for the webhook mode indicating that the controller is running inside of the Kubernetes cluster it - // is serving. - ModeService = "service" - // ModeURL is a constant for the webhook mode indicating that the controller is running outside of the Kubernetes cluster it - // is serving. If this is set then a URL is required for configuration. - ModeURL = "url" - // ModeURLWithServiceName is a constant for the webhook mode indicating that the controller is running outside of the Kubernetes cluster it - // is serving but in the same cluster like the kube-apiserver. If this is set then a URL is required for configuration. - ModeURLWithServiceName = "url-service" -) - -// PrefixedName does not prefix the component name if it starts with "gardener-". Otherwise, it prefixes it with -// "gardener-extension-". -func PrefixedName(componentName string) string { - if !strings.HasPrefix(componentName, "gardener-") { - return NamePrefix + componentName - } - return componentName -} - -// BuildWebhookConfigs builds MutatingWebhookConfiguration objects for seed and shoots from the given webhooks slice. -func BuildWebhookConfigs( - webhooks []*Webhook, - c client.Client, - namespace, providerName string, - servicePort int, - mode, url string, - caBundle []byte, -) ( - seedWebhookConfig client.Object, - shootWebhookConfig *admissionregistrationv1.MutatingWebhookConfiguration, - err error, -) { - var ( - exact = admissionregistrationv1.Exact - sideEffects = admissionregistrationv1.SideEffectClassNone - - seedWebhooks []admissionregistrationv1.MutatingWebhook - shootWebhooks []admissionregistrationv1.MutatingWebhook - ) - - for _, webhook := range webhooks { - var rules []admissionregistrationv1.RuleWithOperations - - for _, t := range webhook.Types { - rule, err := buildRule(c, t) - if err != nil { - return nil, nil, err - } - rules = append(rules, *rule) - } - - webhookToRegister := admissionregistrationv1.MutatingWebhook{ - AdmissionReviewVersions: []string{"v1", "v1beta1"}, - Name: fmt.Sprintf("%s.%s.extensions.gardener.cloud", webhook.Name, strings.TrimPrefix(providerName, "provider-")), - NamespaceSelector: webhook.Selector, - ObjectSelector: webhook.ObjectSelector, - Rules: rules, - SideEffects: &sideEffects, - TimeoutSeconds: pointer.Int32(10), - } - - if webhook.TimeoutSeconds != nil { - webhookToRegister.TimeoutSeconds = webhook.TimeoutSeconds - } - - shootMode := ModeURLWithServiceName - if mode == ModeURL { - shootMode = ModeURL - } - - switch webhook.Target { - case TargetSeed: - webhookToRegister.FailurePolicy = getFailurePolicy(admissionregistrationv1.Fail, webhook.FailurePolicy) - webhookToRegister.MatchPolicy = &exact - webhookToRegister.ClientConfig = BuildClientConfigFor(webhook.Path, namespace, providerName, servicePort, mode, url, caBundle) - seedWebhooks = append(seedWebhooks, webhookToRegister) - case TargetShoot: - webhookToRegister.FailurePolicy = getFailurePolicy(admissionregistrationv1.Ignore, webhook.FailurePolicy) - webhookToRegister.MatchPolicy = &exact - webhookToRegister.ClientConfig = BuildClientConfigFor(webhook.Path, namespace, providerName, servicePort, shootMode, url, caBundle) - shootWebhooks = append(shootWebhooks, webhookToRegister) - default: - return nil, nil, fmt.Errorf("invalid webhook target: %s", webhook.Target) - } - } - - // if all webhooks for one target are removed in a new version, extensions need to explicitly delete the respective - // webhook config - if len(seedWebhooks) > 0 { - seedWebhookConfig = &admissionregistrationv1.MutatingWebhookConfiguration{ - ObjectMeta: metav1.ObjectMeta{ - Name: NamePrefix + providerName, - Labels: map[string]string{v1beta1constants.LabelExcludeWebhookFromRemediation: "true"}, - }, - Webhooks: seedWebhooks, - } - } - - if len(shootWebhooks) > 0 { - shootWebhookConfig = &admissionregistrationv1.MutatingWebhookConfiguration{ - ObjectMeta: metav1.ObjectMeta{ - Name: NamePrefix + providerName + NameSuffixShoot, - Labels: map[string]string{v1beta1constants.LabelExcludeWebhookFromRemediation: "true"}, - }, - Webhooks: shootWebhooks, - } - } - - return seedWebhookConfig, shootWebhookConfig, nil -} - -// ReconcileSeedWebhookConfig reconciles the given webhook config in the seed cluster. -// If a CA bundle is given, it is injected it into all desired webhooks. If not, the CA bundle from the webhook config -// on the cluster (if any) is kept. -func ReconcileSeedWebhookConfig(ctx context.Context, c client.Client, webhookConfig client.Object, ownerNamespace string, caBundle []byte) error { - var ownerReference *metav1.OwnerReference - if len(ownerNamespace) > 0 { - ns := &corev1.Namespace{} - if err := c.Get(ctx, client.ObjectKey{Name: ownerNamespace}, ns); err != nil { - return err - } - ownerReference = metav1.NewControllerRef(ns, corev1.SchemeGroupVersion.WithKind("Namespace")) - ownerReference.BlockOwnerDeletion = pointer.Bool(false) - } - - desiredWebhookConfig := webhookConfig.DeepCopyObject().(client.Object) - - if _, err := controllerutils.GetAndCreateOrStrategicMergePatch(ctx, c, webhookConfig, func() error { - if ownerReference != nil { - webhookConfig.SetOwnerReferences(kubernetes.MergeOwnerReferences(webhookConfig.GetOwnerReferences(), *ownerReference)) - } - - if len(caBundle) == 0 { - var err error - // we can safely assume, that the CA bundles in all webhooks are the same, as we manage it ourselves - caBundle, err = GetCABundleFromWebhookConfig(webhookConfig) - if err != nil { - return err - } - } - - if err := InjectCABundleIntoWebhookConfig(desiredWebhookConfig, caBundle); err != nil { - return err - } - return OverwriteWebhooks(webhookConfig, desiredWebhookConfig) - }); err != nil { - return fmt.Errorf("error reconciling seed webhook config: %w", err) - } - - return nil -} - -// OverwriteWebhooks sets current.Webhooks to desired.Webhooks for all kinds and version of webhook configs. -func OverwriteWebhooks(current, desired client.Object) error { - switch config := current.(type) { - case *admissionregistrationv1.MutatingWebhookConfiguration: - d := desired.(*admissionregistrationv1.MutatingWebhookConfiguration) - config.Webhooks = d.DeepCopy().Webhooks - case *admissionregistrationv1.ValidatingWebhookConfiguration: - d := desired.(*admissionregistrationv1.ValidatingWebhookConfiguration) - config.Webhooks = d.DeepCopy().Webhooks - case *admissionregistrationv1beta1.MutatingWebhookConfiguration: - d := desired.(*admissionregistrationv1beta1.MutatingWebhookConfiguration) - config.Webhooks = d.DeepCopy().Webhooks - case *admissionregistrationv1beta1.ValidatingWebhookConfiguration: - d := desired.(*admissionregistrationv1beta1.ValidatingWebhookConfiguration) - config.Webhooks = d.DeepCopy().Webhooks - default: - return fmt.Errorf("unexpected webhook config type: %T", current) - } - - return nil -} - -// GetCABundleFromWebhookConfig finds the first non-empty Webhooks[0].ClientConfig.CABundle from the given webhook config. -func GetCABundleFromWebhookConfig(obj client.Object) ([]byte, error) { - switch config := obj.(type) { - case *admissionregistrationv1.MutatingWebhookConfiguration: - for _, webhook := range config.Webhooks { - if caBundle := webhook.ClientConfig.CABundle; len(caBundle) > 0 { - return caBundle, nil - } - } - case *admissionregistrationv1.ValidatingWebhookConfiguration: - for _, webhook := range config.Webhooks { - if caBundle := webhook.ClientConfig.CABundle; len(caBundle) > 0 { - return caBundle, nil - } - } - case *admissionregistrationv1beta1.MutatingWebhookConfiguration: - for _, w := range config.Webhooks { - if caBundle := w.ClientConfig.CABundle; len(caBundle) > 0 { - return caBundle, nil - } - } - case *admissionregistrationv1beta1.ValidatingWebhookConfiguration: - for _, webhook := range config.Webhooks { - if caBundle := webhook.ClientConfig.CABundle; len(caBundle) > 0 { - return caBundle, nil - } - } - default: - return nil, fmt.Errorf("unexpected webhook config type: %T", obj) - } - - return nil, nil -} - -// InjectCABundleIntoWebhookConfig sets the given CA bundle in all webhook client config in the given webhook config. -func InjectCABundleIntoWebhookConfig(obj client.Object, caBundle []byte) error { - switch config := obj.(type) { - case *admissionregistrationv1.MutatingWebhookConfiguration: - for i, w := range config.Webhooks { - w.ClientConfig.CABundle = caBundle - config.Webhooks[i] = w - } - case *admissionregistrationv1.ValidatingWebhookConfiguration: - for i, w := range config.Webhooks { - w.ClientConfig.CABundle = caBundle - config.Webhooks[i] = w - } - case *admissionregistrationv1beta1.MutatingWebhookConfiguration: - for i, w := range config.Webhooks { - w.ClientConfig.CABundle = caBundle - config.Webhooks[i] = w - } - case *admissionregistrationv1beta1.ValidatingWebhookConfiguration: - for i, w := range config.Webhooks { - w.ClientConfig.CABundle = caBundle - config.Webhooks[i] = w - } - default: - return fmt.Errorf("unexpected webhook config type: %T", obj) - } - - return nil -} - -func getFailurePolicy(def admissionregistrationv1.FailurePolicyType, overwrite *admissionregistrationv1.FailurePolicyType) *admissionregistrationv1.FailurePolicyType { - if overwrite != nil { - return overwrite - } - return &def -} - -// buildRule creates and returns a RuleWithOperations for the given object type. -func buildRule(c client.Client, t Type) (*admissionregistrationv1.RuleWithOperations, error) { - // Get GVK from the type - gvk, err := apiutil.GVKForObject(t.Obj, c.Scheme()) - if err != nil { - return nil, fmt.Errorf("could not get GroupVersionKind from object %v: %w", t.Obj, err) - } - - // Get REST mapping from GVK - mapping, err := c.RESTMapper().RESTMapping(gvk.GroupKind(), gvk.Version) - if err != nil { - return nil, fmt.Errorf("could not get REST mapping from GroupVersionKind '%s': %w", gvk.String(), err) - } - - resource := mapping.Resource.Resource - if t.Subresource != nil { - resource += fmt.Sprintf("/%s", *t.Subresource) - } - - // Create and return RuleWithOperations - return &admissionregistrationv1.RuleWithOperations{ - Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Create, - admissionregistrationv1.Update, - }, - Rule: admissionregistrationv1.Rule{ - APIGroups: []string{gvk.Group}, - APIVersions: []string{gvk.Version}, - Resources: []string{resource}, - }, - }, nil -} - -// BuildClientConfigFor builds the client config for a webhook. -func BuildClientConfigFor(webhookPath string, namespace, componentName string, servicePort int, mode, url string, caBundle []byte) admissionregistrationv1.WebhookClientConfig { - var ( - path = webhookPath - clientConfig = admissionregistrationv1.WebhookClientConfig{ - // can be empty if injected later on - CABundle: caBundle, - } - ) - - if !strings.HasPrefix(path, "/") { - path = "/" + path - } - - switch mode { - case ModeURL: - clientConfig.URL = pointer.String(fmt.Sprintf("https://%s%s", url, path)) - case ModeURLWithServiceName: - clientConfig.URL = pointer.String(fmt.Sprintf("https://%s.%s:%d%s", PrefixedName(componentName), namespace, servicePort, path)) - case ModeService: - clientConfig.Service = &admissionregistrationv1.ServiceReference{ - Namespace: namespace, - Name: PrefixedName(componentName), - Path: &path, - } - } - - return clientConfig -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/remote_addr.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/remote_addr.go deleted file mode 100644 index 588f5524..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/remote_addr.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2021 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 webhook - -import ( - "context" - "net/http" - - "sigs.k8s.io/controller-runtime/pkg/runtime/inject" -) - -// remoteAddrContextKey is a context key. It will be filled by the remoteAddrInjectingHandler with the received -// request's RemoteAddr field value. -// The associated value will be of type string. -var remoteAddrContextKey = struct{}{} - -// remoteAddrInjectingHandler is a wrapper around a given http.Handler that injects the requests.RemoteAddr into the -// request's context and delegates to the underlying handler. -type remoteAddrInjectingHandler struct { - // Handler is the underlying handler. - http.Handler -} - -// InjectFunc injects into the underlying handler. -func (h remoteAddrInjectingHandler) InjectFunc(f inject.Func) error { - return f(h.Handler) -} - -// ServerHTTP implements http.Handler by delegating to the underlying handler but injecting request.RemoteAddr into -// the request's context. -func (h remoteAddrInjectingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - h.Handler.ServeHTTP(w, r.Clone(context.WithValue(r.Context(), remoteAddrContextKey, r.RemoteAddr))) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/networkpolicy.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/networkpolicy.go deleted file mode 100644 index 3f5e8702..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/networkpolicy.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 shoot - -import ( - "context" - - corev1 "k8s.io/api/core/v1" - networkingv1 "k8s.io/api/networking/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" - "github.com/gardener/gardener/pkg/controllerutils" - "github.com/gardener/gardener/pkg/utils" - kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" -) - -// GetNetworkPolicyMeta returns the network policy object with filled metadata. -func GetNetworkPolicyMeta(shootNamespace, extensionName string) *networkingv1.NetworkPolicy { - return &networkingv1.NetworkPolicy{ObjectMeta: kubernetesutils.ObjectMeta(shootNamespace, "gardener-extension-"+extensionName)} -} - -// EnsureEgressNetworkPolicy ensures that the required egress network policy is installed that allows the kube-apiserver -// running in the given shoot namespace to talk to the extension webhook . -func EnsureEgressNetworkPolicy(ctx context.Context, c client.Client, shootNamespace, extensionNamespace, extensionName string, port int) error { - networkPolicy := GetNetworkPolicyMeta(shootNamespace, extensionName) - _, err := controllerutils.GetAndCreateOrMergePatch(ctx, c, networkPolicy, func() error { - networkPolicy.Spec = networkingv1.NetworkPolicySpec{ - PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress}, - Egress: []networkingv1.NetworkPolicyEgressRule{ - { - Ports: []networkingv1.NetworkPolicyPort{ - { - Port: utils.IntStrPtrFromInt(port), - Protocol: utils.ProtocolPtr(corev1.ProtocolTCP), - }, - }, - To: []networkingv1.NetworkPolicyPeer{ - { - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - corev1.LabelMetadataName: extensionNamespace, - }, - }, - PodSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": "gardener-extension-" + extensionName, - }, - }, - }, - }, - }, - }, - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - v1beta1constants.LabelApp: v1beta1constants.LabelKubernetes, - v1beta1constants.LabelRole: v1beta1constants.LabelAPIServer, - }, - }, - } - return nil - }) - return err -} - -// EnsureIngressNetworkPolicy ensures that the required ingress network policy is installed that allows the -// kube-apiservers of shoot namespaces to talk to the extension webhook. -func EnsureIngressNetworkPolicy(ctx context.Context, c client.Client, extensionNamespace, extensionName string, port int) error { - networkPolicy := &networkingv1.NetworkPolicy{ObjectMeta: metav1.ObjectMeta{Namespace: extensionNamespace, Name: "ingress-from-all-shoots-kube-apiserver"}} - _, err := controllerutils.GetAndCreateOrMergePatch(ctx, c, networkPolicy, func() error { - networkPolicy.Spec = networkingv1.NetworkPolicySpec{ - PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress}, - Ingress: []networkingv1.NetworkPolicyIngressRule{ - { - Ports: []networkingv1.NetworkPolicyPort{ - { - Port: utils.IntStrPtrFromInt(port), - Protocol: utils.ProtocolPtr(corev1.ProtocolTCP), - }, - }, - From: []networkingv1.NetworkPolicyPeer{ - { - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - v1beta1constants.GardenRole: v1beta1constants.GardenRoleShoot, - }, - }, - PodSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - v1beta1constants.LabelApp: v1beta1constants.LabelKubernetes, - v1beta1constants.LabelRole: v1beta1constants.LabelAPIServer, - }, - }, - }, - }, - }, - }, - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": "gardener-extension-" + extensionName, - }, - }, - } - return nil - }) - return err -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/shoot.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/shoot.go deleted file mode 100644 index eea08b92..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/shoot.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 shoot - -import ( - "fmt" - - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - extensionswebhook "github.com/gardener/gardener/extensions/pkg/webhook" - v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" -) - -const ( - // WebhookName is the name of the shoot webhook. - WebhookName = "shoot" - // KindSystem is used for webhooks which should only apply to the to the kube-system namespace. - KindSystem = "system" -) - -var logger = log.Log.WithName("shoot-webhook") - -// Args are arguments for creating a webhook targeting a shoot. -type Args struct { - // Types is a list of resource types. - Types []extensionswebhook.Type - // Mutator is a mutator to be used by the admission handler. It doesn't need the shoot client. - Mutator extensionswebhook.Mutator - // MutatorWithShootClient is a mutator to be used by the admission handler. It needs the shoot client. - MutatorWithShootClient extensionswebhook.MutatorWithShootClient - // FailurePolicy is the failure policy for the webhook (defaults to Ignore). - FailurePolicy *admissionregistrationv1.FailurePolicyType -} - -// New creates a new webhook with the shoot as target cluster. -func New(mgr manager.Manager, args Args) (*extensionswebhook.Webhook, error) { - logger.Info("Creating webhook", "name", WebhookName) - - // Build namespace selector from the webhook kind and provider - namespaceSelector, err := buildSelector() - if err != nil { - return nil, err - } - - wh := &extensionswebhook.Webhook{ - Name: WebhookName, - Types: args.Types, - Path: WebhookName, - Target: extensionswebhook.TargetShoot, - Selector: namespaceSelector, - FailurePolicy: args.FailurePolicy, - } - - switch { - case args.Mutator != nil: - handler, err := extensionswebhook.NewBuilder(mgr, logger).WithMutator(args.Mutator, args.Types...).Build() - if err != nil { - return nil, err - } - - wh.Webhook = &admission.Webhook{Handler: handler, RecoverPanic: true} - return wh, nil - - case args.MutatorWithShootClient != nil: - handler, err := extensionswebhook.NewHandlerWithShootClient(mgr, args.Types, args.MutatorWithShootClient, logger) - if err != nil { - return nil, err - } - - wh.Handler = handler - return wh, nil - } - - return nil, fmt.Errorf("neither mutator nor mutator with shoot client is set") -} - -// buildSelector creates and returns a LabelSelector for the given webhook kind and provider. -func buildSelector() (*metav1.LabelSelector, error) { - // Create and return LabelSelector - return &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - {Key: v1beta1constants.GardenerPurpose, Operator: metav1.LabelSelectorOpIn, Values: []string{metav1.NamespaceSystem}}, - }, - }, nil -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/webhook.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/webhook.go deleted file mode 100644 index 6bfb81f2..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/webhook.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2022 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 shoot - -import ( - "context" - "fmt" - - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - corev1 "k8s.io/api/core/v1" - networkingv1 "k8s.io/api/networking/v1" - "k8s.io/apimachinery/pkg/api/errors" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/gardener/gardener/extensions/pkg/controller" - v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" - "github.com/gardener/gardener/pkg/client/kubernetes" - "github.com/gardener/gardener/pkg/extensions" - "github.com/gardener/gardener/pkg/utils" - "github.com/gardener/gardener/pkg/utils/flow" - kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" - "github.com/gardener/gardener/pkg/utils/managedresources" -) - -// ReconcileWebhookConfig deploys the shoot webhook configuration, i.e., a network policy to allow the -// kube-apiserver to talk to the extension, and a managed resource that contains the MutatingWebhookConfiguration. -func ReconcileWebhookConfig( - ctx context.Context, - c client.Client, - shootNamespace string, - extensionNamespace string, - extensionName string, - managedResourceName string, - serverPort int, - shootWebhookConfig *admissionregistrationv1.MutatingWebhookConfiguration, - cluster *controller.Cluster, -) error { - if err := EnsureEgressNetworkPolicy(ctx, c, shootNamespace, extensionNamespace, extensionName, serverPort); err != nil { - return fmt.Errorf("could not create or update network policy for shoot webhooks in namespace '%s': %w", shootNamespace, err) - } - - if cluster.Shoot == nil { - return fmt.Errorf("no shoot found in cluster resource") - } - - data, err := managedresources. - NewRegistry(kubernetes.ShootScheme, kubernetes.ShootCodec, kubernetes.ShootSerializer). - AddAllAndSerialize(shootWebhookConfig) - if err != nil { - return err - } - - if err := managedresources.Create(ctx, c, shootNamespace, managedResourceName, nil, false, "", data, nil, nil, nil); err != nil { - return fmt.Errorf("could not create or update managed resource '%s/%s' containing shoot webhooks: %w", shootNamespace, managedResourceName, err) - } - - return nil -} - -// ReconcileWebhooksForAllNamespaces reconciles the shoot webhooks in all shoot namespaces of the given -// provider type. This is necessary in case the webhook port is changed (otherwise, the network policy would only be -// updated again as part of the ControlPlane reconciliation which might only happen in the next 24h). -func ReconcileWebhooksForAllNamespaces( - ctx context.Context, - c client.Client, - extensionNamespace string, - extensionName string, - managedResourceName string, - shootNamespaceSelector map[string]string, - port int, - shootWebhookConfig *admissionregistrationv1.MutatingWebhookConfiguration, -) error { - namespaceList := &corev1.NamespaceList{} - if err := c.List(ctx, namespaceList, client.MatchingLabels(utils.MergeStringMaps(map[string]string{ - v1beta1constants.GardenRole: v1beta1constants.GardenRoleShoot, - }, shootNamespaceSelector))); err != nil { - return err - } - - fns := make([]flow.TaskFn, 0, len(namespaceList.Items)+1) - - fns = append(fns, func(ctx context.Context) error { - return EnsureIngressNetworkPolicy(ctx, c, extensionNamespace, extensionName, port) - }) - - for _, namespace := range namespaceList.Items { - var ( - networkPolicy = GetNetworkPolicyMeta(namespace.Name, extensionName) - namespaceName = namespace.Name - networkPolicyName = networkPolicy.Name - ) - - fns = append(fns, func(ctx context.Context) error { - if err := c.Get(ctx, kubernetesutils.Key(namespaceName, networkPolicyName), &networkingv1.NetworkPolicy{}); err != nil { - if !errors.IsNotFound(err) { - return err - } - return nil - } - - cluster, err := extensions.GetCluster(ctx, c, namespaceName) - if err != nil { - return err - } - - return ReconcileWebhookConfig(ctx, c, namespaceName, extensionNamespace, extensionName, managedResourceName, port, shootWebhookConfig.DeepCopy(), cluster) - }) - } - - return flow.Parallel(fns...)(ctx) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/utils.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/utils.go deleted file mode 100644 index ab31ad9a..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/utils.go +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 webhook - -import ( - "reflect" - "regexp" - "strings" - - "github.com/coreos/go-systemd/v22/unit" - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - - extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" -) - -// LogMutation provides a log message. -func LogMutation(logger logr.Logger, kind, namespace, name string) { - logger.Info("Mutating resource", "kind", kind, "namespace", namespace, "name", name) -} - -// AppendUniqueUnit appens a unit only if it does not exist. -func AppendUniqueUnit(units *[]extensionsv1alpha1.Unit, unit extensionsv1alpha1.Unit) { - for _, un := range *units { - if un.Name == unit.Name { - return - } - } - *units = append(*units, unit) -} - -// DeserializeCommandLine de-serializes the given string to a slice of command line elements by splitting it -// on white space and the "\" character. -func DeserializeCommandLine(s string) []string { - return regexp.MustCompile(`[\\\s]+`).Split(s, -1) -} - -// SerializeCommandLine serializes the given command line elements slice to a string by joining the first -// n+1 elements with a space " ", and all subsequent elements with the given separator. -func SerializeCommandLine(command []string, n int, sep string) string { - if len(command) <= n { - return strings.Join(command, " ") - } - if n == 0 { - return strings.Join(command, sep) - } - return strings.Join(command[0:n], " ") + " " + strings.Join(command[n:], sep) -} - -// ContainerWithName returns the container with the given name if it exists in the given slice, nil otherwise. -func ContainerWithName(containers []corev1.Container, name string) *corev1.Container { - if i := containerWithNameIndex(containers, name); i >= 0 { - return &containers[i] - } - return nil -} - -// PVCWithName returns the PersistentVolumeClaim with the given name if it exists in the given slice, nil otherwise. -func PVCWithName(pvcs []corev1.PersistentVolumeClaim, name string) *corev1.PersistentVolumeClaim { - if i := pvcWithNameIndex(pvcs, name); i >= 0 { - return &pvcs[i] - } - return nil -} - -// UnitWithName returns the unit with the given name if it exists in the given slice, nil otherwise. -func UnitWithName(units []extensionsv1alpha1.Unit, name string) *extensionsv1alpha1.Unit { - if i := unitWithNameIndex(units, name); i >= 0 { - return &units[i] - } - return nil -} - -// FileWithPath returns the file with the given path if it exists in the given slice, nil otherwise. -func FileWithPath(files []extensionsv1alpha1.File, path string) *extensionsv1alpha1.File { - if i := fileWithPathIndex(files, path); i >= 0 { - return &files[i] - } - return nil -} - -// UnitOptionWithSectionAndName returns the unit option with the given section and name if it exists in the given slice, nil otherwise. -func UnitOptionWithSectionAndName(opts []*unit.UnitOption, section, name string) *unit.UnitOption { - if i := unitOptionWithSectionAndNameIndex(opts, section, name); i >= 0 { - return opts[i] - } - return nil -} - -// EnsureStringWithPrefix ensures that a string having the given prefix exists in the given slice -// with a value equal to prefix + value. -func EnsureStringWithPrefix(items []string, prefix, value string) []string { - item := prefix + value - if i := StringWithPrefixIndex(items, prefix); i < 0 { - items = append(items, item) - } else if items[i] != item { - items = append(append(items[:i], item), items[i+1:]...) - } - return items -} - -// EnsureNoStringWithPrefix ensures that a string having the given prefix does not exist in the given slice. -func EnsureNoStringWithPrefix(items []string, prefix string) []string { - if i := StringWithPrefixIndex(items, prefix); i >= 0 { - items = append(items[:i], items[i+1:]...) - } - return items -} - -// EnsureStringWithPrefixContains ensures that a string having the given prefix exists in the given slice -// and contains the given value in a list separated by sep. -func EnsureStringWithPrefixContains(items []string, prefix, value, sep string) []string { - if i := StringWithPrefixIndex(items, prefix); i < 0 { - items = append(items, prefix+value) - } else { - valuesList := strings.TrimPrefix(items[i], prefix) - var values []string - if valuesList != "" { - values = strings.Split(valuesList, sep) - } - if j := StringIndex(values, value); j < 0 { - values = append(values, value) - items = append(append(items[:i], prefix+strings.Join(values, sep)), items[i+1:]...) - } - } - return items -} - -// EnsureNoStringWithPrefixContains ensures that either a string having the given prefix does not exist in the given slice, -// or it doesn't contain the given value in a list separated by sep. -func EnsureNoStringWithPrefixContains(items []string, prefix, value, sep string) []string { - if i := StringWithPrefixIndex(items, prefix); i >= 0 { - values := strings.Split(strings.TrimPrefix(items[i], prefix), sep) - if j := StringIndex(values, value); j >= 0 { - values = append(values[:j], values[j+1:]...) - items = append(append(items[:i], prefix+strings.Join(values, sep)), items[i+1:]...) - } - } - return items -} - -// EnsureEnvVarWithName ensures that a EnvVar with a name equal to the name of the given EnvVar exists -// in the given slice and is equal to the given EnvVar. -func EnsureEnvVarWithName(items []corev1.EnvVar, item corev1.EnvVar) []corev1.EnvVar { - if i := envVarWithNameIndex(items, item.Name); i < 0 { - items = append(items, item) - } else if !reflect.DeepEqual(items[i], item) { - items = append(append(items[:i], item), items[i+1:]...) - } - return items -} - -// EnsureNoEnvVarWithName ensures that a EnvVar with the given name does not exist in the given slice. -func EnsureNoEnvVarWithName(items []corev1.EnvVar, name string) []corev1.EnvVar { - if i := envVarWithNameIndex(items, name); i >= 0 { - items = append(items[:i], items[i+1:]...) - } - return items -} - -// EnsureVolumeMountWithName ensures that a VolumeMount with a name equal to the name of the given VolumeMount exists -// in the given slice and is equal to the given VolumeMount. -func EnsureVolumeMountWithName(items []corev1.VolumeMount, item corev1.VolumeMount) []corev1.VolumeMount { - if i := volumeMountWithNameIndex(items, item.Name); i < 0 { - items = append(items, item) - } else if !reflect.DeepEqual(items[i], item) { - items = append(append(items[:i], item), items[i+1:]...) - } - return items -} - -// EnsureNoVolumeMountWithName ensures that a VolumeMount with the given name does not exist in the given slice. -func EnsureNoVolumeMountWithName(items []corev1.VolumeMount, name string) []corev1.VolumeMount { - if i := volumeMountWithNameIndex(items, name); i >= 0 { - items = append(items[:i], items[i+1:]...) - } - return items -} - -// EnsureVolumeWithName ensures that a Volume with a name equal to the name of the given Volume exists -// in the given slice and is equal to the given Volume. -func EnsureVolumeWithName(items []corev1.Volume, item corev1.Volume) []corev1.Volume { - if i := volumeWithNameIndex(items, item.Name); i < 0 { - items = append(items, item) - } else if !reflect.DeepEqual(items[i], item) { - items = append(append(items[:i], item), items[i+1:]...) - } - return items -} - -// EnsureNoVolumeWithName ensures that a Volume with the given name does not exist in the given slice. -func EnsureNoVolumeWithName(items []corev1.Volume, name string) []corev1.Volume { - if i := volumeWithNameIndex(items, name); i >= 0 { - items = append(items[:i], items[i+1:]...) - } - return items -} - -// EnsureContainerWithName ensures that a Container with a name equal to the name of the given Container exists -// in the given slice and is equal to the given Container. -func EnsureContainerWithName(items []corev1.Container, item corev1.Container) []corev1.Container { - if i := containerWithNameIndex(items, item.Name); i < 0 { - items = append(items, item) - } else if !reflect.DeepEqual(items[i], item) { - items = append(append(items[:i], item), items[i+1:]...) - } - return items -} - -// EnsureNoContainerWithName ensures that a Container with the given name does not exist in the given slice. -func EnsureNoContainerWithName(items []corev1.Container, name string) []corev1.Container { - if i := containerWithNameIndex(items, name); i >= 0 { - items = append(items[:i], items[i+1:]...) - } - return items -} - -// EnsurePVCWithName ensures that a PVC with a name equal to the name of the given PVC exists -// in the given slice and is equal to the given PVC. -func EnsurePVCWithName(items []corev1.PersistentVolumeClaim, item corev1.PersistentVolumeClaim) []corev1.PersistentVolumeClaim { - if i := pvcWithNameIndex(items, item.Name); i < 0 { - items = append(items, item) - } else if !reflect.DeepEqual(items[i], item) { - items = append(append(items[:i], item), items[i+1:]...) - } - return items -} - -// EnsureNoPVCWithName ensures that a PVC with the given name does not exist in the given slice. -func EnsureNoPVCWithName(items []corev1.PersistentVolumeClaim, name string) []corev1.PersistentVolumeClaim { - if i := pvcWithNameIndex(items, name); i >= 0 { - items = append(items[:i], items[i+1:]...) - } - return items -} - -// EnsureUnitOption ensures the given unit option exist in the given slice. -func EnsureUnitOption(items []*unit.UnitOption, item *unit.UnitOption) []*unit.UnitOption { - if i := unitOptionIndex(items, item); i < 0 { - items = append(items, item) - } - return items -} - -// EnsureFileWithPath ensures that a file with a path equal to the path of the given file exists in the given slice -// and is equal to the given file. -func EnsureFileWithPath(items []extensionsv1alpha1.File, item extensionsv1alpha1.File) []extensionsv1alpha1.File { - if i := fileWithPathIndex(items, item.Path); i < 0 { - items = append(items, item) - } else if !reflect.DeepEqual(items[i], item) { - items = append(append(items[:i], item), items[i+1:]...) - } - return items -} - -// EnsureAnnotationOrLabel ensures the given key/value exists in the annotationOrLabelMap map. -func EnsureAnnotationOrLabel(annotationOrLabelMap map[string]string, key, value string) map[string]string { - if annotationOrLabelMap == nil { - annotationOrLabelMap = make(map[string]string, 1) - } - annotationOrLabelMap[key] = value - return annotationOrLabelMap -} - -// StringIndex returns the index of the first occurrence of the given string in the given slice, or -1 if not found. -func StringIndex(items []string, value string) int { - for i, item := range items { - if item == value { - return i - } - } - return -1 -} - -// StringWithPrefixIndex returns the index of the first occurrence of a string having the given prefix in the given slice, or -1 if not found. -func StringWithPrefixIndex(items []string, prefix string) int { - for i, item := range items { - if strings.HasPrefix(item, prefix) { - return i - } - } - return -1 -} - -func containerWithNameIndex(items []corev1.Container, name string) int { - for i, item := range items { - if item.Name == name { - return i - } - } - return -1 -} - -func unitWithNameIndex(items []extensionsv1alpha1.Unit, name string) int { - for i, item := range items { - if item.Name == name { - return i - } - } - return -1 -} - -func fileWithPathIndex(items []extensionsv1alpha1.File, path string) int { - for i, item := range items { - if item.Path == path { - return i - } - } - return -1 -} - -func unitOptionWithSectionAndNameIndex(items []*unit.UnitOption, section, name string) int { - for i, item := range items { - if item.Section == section && item.Name == name { - return i - } - } - return -1 -} - -func unitOptionIndex(items []*unit.UnitOption, item *unit.UnitOption) int { - for i := range items { - if reflect.DeepEqual(items[i], item) { - return i - } - } - return -1 -} - -func envVarWithNameIndex(items []corev1.EnvVar, name string) int { - for i, item := range items { - if item.Name == name { - return i - } - } - return -1 -} - -func volumeMountWithNameIndex(items []corev1.VolumeMount, name string) int { - for i, item := range items { - if item.Name == name { - return i - } - } - return -1 -} - -func volumeWithNameIndex(items []corev1.Volume, name string) int { - for i, item := range items { - if item.Name == name { - return i - } - } - return -1 -} - -func pvcWithNameIndex(items []corev1.PersistentVolumeClaim, name string) int { - for i, item := range items { - if item.Name == name { - return i - } - } - return -1 -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/validator.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/validator.go deleted file mode 100644 index d821707c..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/validator.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 webhook - -import ( - "context" - "fmt" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/runtime/inject" -) - -// Validator validates objects. -type Validator interface { - Validate(ctx context.Context, new, old client.Object) error -} - -type validationWrapper struct { - Validator -} - -// Mutate implements the `Mutator` interface and calls the `Validate` function of the underlying validator. -func (d *validationWrapper) Mutate(ctx context.Context, new, old client.Object) error { - return d.Validate(ctx, new, old) -} - -// InjectFunc calls the inject.Func on the handler mutators. -func (d *validationWrapper) InjectFunc(f inject.Func) error { - if err := f(d.Validator); err != nil { - return fmt.Errorf("could not inject into the validator: %w", err) - } - return nil -} - -func hybridValidator(val Validator) Mutator { - return &validationWrapper{val} -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/webhook.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/webhook.go deleted file mode 100644 index bc23c249..00000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/webhook.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// 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 webhook - -import ( - "net/http" - - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -const ( - // TargetSeed defines that the webhook is to be installed in the seed. - TargetSeed = "seed" - // TargetShoot defines that the webhook is to be installed in the shoot. - TargetShoot = "shoot" -) - -// Webhook is the specification of a webhook. -type Webhook struct { - Name string - Provider string - Path string - Target string - Types []Type - Webhook *admission.Webhook - Handler http.Handler - Selector *metav1.LabelSelector - ObjectSelector *metav1.LabelSelector - FailurePolicy *admissionregistrationv1.FailurePolicyType - TimeoutSeconds *int32 -} - -// Type contains information about the Kubernetes object types and subresources the webhook acts upon. -type Type struct { - Obj client.Object - Subresource *string -} - -// Args contains Webhook creation arguments. -type Args struct { - Provider string - Name string - Path string - Predicates []predicate.Predicate - Validators map[Validator][]Type - Mutators map[Mutator][]Type -} - -// New creates a new Webhook with the given args. -func New(mgr manager.Manager, args Args) (*Webhook, error) { - logger := log.Log.WithName(args.Name).WithValues("provider", args.Provider) - - // Create handler - builder := NewBuilder(mgr, logger) - - for val, objs := range args.Validators { - builder.WithValidator(val, objs...) - } - - for mut, objs := range args.Mutators { - builder.WithMutator(mut, objs...) - } - - builder.WithPredicates(args.Predicates...) - - handler, err := builder.Build() - if err != nil { - return nil, err - } - - // Create webhook - logger.Info("Creating webhook") - - return &Webhook{ - Path: args.Path, - Webhook: &admission.Webhook{Handler: handler, RecoverPanic: true}, - }, nil -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 921c00d8..b67b314e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -175,9 +175,6 @@ github.com/chrismellard/docker-credential-acr-env/pkg/token ## explicit; go 1.19 github.com/containerd/stargz-snapshotter/estargz github.com/containerd/stargz-snapshotter/estargz/errorutil -# github.com/coreos/go-systemd/v22 v22.3.2 -## explicit; go 1.12 -github.com/coreos/go-systemd/v22/unit # github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 ## explicit github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer @@ -268,9 +265,6 @@ github.com/gardener/gardener/extensions/pkg/controller/heartbeat/cmd github.com/gardener/gardener/extensions/pkg/predicate github.com/gardener/gardener/extensions/pkg/util github.com/gardener/gardener/extensions/pkg/util/secret/manager -github.com/gardener/gardener/extensions/pkg/webhook -github.com/gardener/gardener/extensions/pkg/webhook/certificates -github.com/gardener/gardener/extensions/pkg/webhook/shoot github.com/gardener/gardener/hack github.com/gardener/gardener/hack/.ci github.com/gardener/gardener/hack/api-reference/template