├── docs ├── .gitignore ├── themes │ ├── hugo-geekdocs │ │ ├── VERSION │ │ ├── layouts │ │ │ ├── taxonomy │ │ │ │ ├── list.html │ │ │ │ └── taxonomy.html │ │ │ ├── partials │ │ │ │ ├── head │ │ │ │ │ ├── custom.html │ │ │ │ │ ├── favicons.html │ │ │ │ │ ├── meta.html │ │ │ │ │ └── others.html │ │ │ │ ├── svg-icon-symbols.html │ │ │ │ ├── title.html │ │ │ │ ├── content.html │ │ │ │ ├── search.html │ │ │ │ ├── menu.html │ │ │ │ ├── foot.html │ │ │ │ ├── menu-extra.html │ │ │ │ ├── site-footer.html │ │ │ │ ├── menu-filetree.html │ │ │ │ ├── page-footer.html │ │ │ │ ├── menu-bundle.html │ │ │ │ ├── page-header.html │ │ │ │ └── site-header.html │ │ │ ├── shortcodes │ │ │ │ ├── hint.html │ │ │ │ ├── icon.html │ │ │ │ ├── columns.html │ │ │ │ ├── toc.html │ │ │ │ ├── tab.html │ │ │ │ ├── mermaid.html │ │ │ │ ├── expand.html │ │ │ │ ├── include.html │ │ │ │ ├── tabs.html │ │ │ │ ├── button.html │ │ │ │ ├── katex.html │ │ │ │ ├── toc-tree.html │ │ │ │ └── img.html │ │ │ ├── _default │ │ │ │ ├── _markup │ │ │ │ │ ├── render-image.html │ │ │ │ │ ├── render-link.html │ │ │ │ │ └── render-heading.html │ │ │ │ ├── list.html │ │ │ │ ├── single.html │ │ │ │ └── baseof.html │ │ │ ├── posts │ │ │ │ ├── single.html │ │ │ │ └── list.html │ │ │ └── 404.html │ │ ├── static │ │ │ ├── custom.css │ │ │ ├── js │ │ │ │ ├── clipboard-loader-f0b5fbd5f6.min.js │ │ │ │ ├── katex-loader-3cfedeea38.min.js │ │ │ │ ├── mermaid-loader-1bd1515cbf.min.js │ │ │ │ ├── groupBy-174feb11c7.min.js │ │ │ │ ├── darkmode-ce906ea916.min.js │ │ │ │ └── auto-render-e6e57901eb.min.js │ │ │ ├── favicon │ │ │ │ ├── favicon.ico │ │ │ │ ├── mstile-70x70.png │ │ │ │ ├── favicon-16x16.png │ │ │ │ ├── favicon-32x32.png │ │ │ │ ├── mstile-144x144.png │ │ │ │ ├── mstile-150x150.png │ │ │ │ ├── mstile-310x150.png │ │ │ │ ├── mstile-310x310.png │ │ │ │ ├── apple-touch-icon.png │ │ │ │ ├── android-chrome-192x192.png │ │ │ │ ├── android-chrome-512x512.png │ │ │ │ ├── browserconfig.xml │ │ │ │ ├── site.webmanifest │ │ │ │ └── safari-pinned-tab.svg │ │ │ ├── fonts │ │ │ │ ├── Metropolis.woff │ │ │ │ ├── GeekdocIcons.woff │ │ │ │ ├── GeekdocIcons.woff2 │ │ │ │ ├── Metropolis.woff2 │ │ │ │ ├── KaTeX_Main-Bold.ttf │ │ │ │ ├── KaTeX_Main-Bold.woff │ │ │ │ ├── LiberationMono.woff │ │ │ │ ├── LiberationMono.woff2 │ │ │ │ ├── LiberationSans.woff │ │ │ │ ├── LiberationSans.woff2 │ │ │ │ ├── KaTeX_AMS-Regular.ttf │ │ │ │ ├── KaTeX_AMS-Regular.woff │ │ │ │ ├── KaTeX_AMS-Regular.woff2 │ │ │ │ ├── KaTeX_Fraktur-Bold.ttf │ │ │ │ ├── KaTeX_Fraktur-Bold.woff │ │ │ │ ├── KaTeX_Main-Bold.woff2 │ │ │ │ ├── KaTeX_Main-Italic.ttf │ │ │ │ ├── KaTeX_Main-Italic.woff │ │ │ │ ├── KaTeX_Main-Italic.woff2 │ │ │ │ ├── KaTeX_Main-Regular.ttf │ │ │ │ ├── KaTeX_Main-Regular.woff │ │ │ │ ├── KaTeX_Math-Italic.ttf │ │ │ │ ├── KaTeX_Math-Italic.woff │ │ │ │ ├── KaTeX_Math-Italic.woff2 │ │ │ │ ├── KaTeX_Size1-Regular.ttf │ │ │ │ ├── KaTeX_Size2-Regular.ttf │ │ │ │ ├── KaTeX_Size3-Regular.ttf │ │ │ │ ├── KaTeX_Size4-Regular.ttf │ │ │ │ ├── KaTeX_Fraktur-Bold.woff2 │ │ │ │ ├── KaTeX_Fraktur-Regular.ttf │ │ │ │ ├── KaTeX_Main-BoldItalic.ttf │ │ │ │ ├── KaTeX_Main-Regular.woff2 │ │ │ │ ├── KaTeX_Math-BoldItalic.ttf │ │ │ │ ├── KaTeX_SansSerif-Bold.ttf │ │ │ │ ├── KaTeX_SansSerif-Bold.woff │ │ │ │ ├── KaTeX_Script-Regular.ttf │ │ │ │ ├── KaTeX_Script-Regular.woff │ │ │ │ ├── KaTeX_Size1-Regular.woff │ │ │ │ ├── KaTeX_Size1-Regular.woff2 │ │ │ │ ├── KaTeX_Size2-Regular.woff │ │ │ │ ├── KaTeX_Size2-Regular.woff2 │ │ │ │ ├── KaTeX_Size3-Regular.woff │ │ │ │ ├── KaTeX_Size3-Regular.woff2 │ │ │ │ ├── KaTeX_Size4-Regular.woff │ │ │ │ ├── KaTeX_Size4-Regular.woff2 │ │ │ │ ├── LiberationSans-Bold.woff │ │ │ │ ├── LiberationSans-Bold.woff2 │ │ │ │ ├── KaTeX_Caligraphic-Bold.ttf │ │ │ │ ├── KaTeX_Caligraphic-Bold.woff │ │ │ │ ├── KaTeX_Caligraphic-Bold.woff2 │ │ │ │ ├── KaTeX_Fraktur-Regular.woff │ │ │ │ ├── KaTeX_Fraktur-Regular.woff2 │ │ │ │ ├── KaTeX_Main-BoldItalic.woff │ │ │ │ ├── KaTeX_Main-BoldItalic.woff2 │ │ │ │ ├── KaTeX_Math-BoldItalic.woff │ │ │ │ ├── KaTeX_Math-BoldItalic.woff2 │ │ │ │ ├── KaTeX_SansSerif-Bold.woff2 │ │ │ │ ├── KaTeX_SansSerif-Italic.ttf │ │ │ │ ├── KaTeX_SansSerif-Italic.woff │ │ │ │ ├── KaTeX_SansSerif-Italic.woff2 │ │ │ │ ├── KaTeX_SansSerif-Regular.ttf │ │ │ │ ├── KaTeX_SansSerif-Regular.woff │ │ │ │ ├── KaTeX_Script-Regular.woff2 │ │ │ │ ├── KaTeX_Typewriter-Regular.ttf │ │ │ │ ├── LiberationSans-Italic.woff │ │ │ │ ├── LiberationSans-Italic.woff2 │ │ │ │ ├── KaTeX_Caligraphic-Regular.ttf │ │ │ │ ├── KaTeX_Caligraphic-Regular.woff │ │ │ │ ├── KaTeX_SansSerif-Regular.woff2 │ │ │ │ ├── KaTeX_Typewriter-Regular.woff │ │ │ │ ├── KaTeX_Typewriter-Regular.woff2 │ │ │ │ ├── LiberationSans-BoldItalic.woff │ │ │ │ ├── KaTeX_Caligraphic-Regular.woff2 │ │ │ │ └── LiberationSans-BoldItalic.woff2 │ │ │ ├── print-f79fc3e5d7.min.css │ │ │ ├── mobile-c344439d04.min.css │ │ │ └── brand.svg │ │ ├── data │ │ │ ├── assets-static.json │ │ │ └── assets.json │ │ ├── archetypes │ │ │ ├── posts.md │ │ │ └── docs.md │ │ ├── images │ │ │ ├── tn.png │ │ │ ├── readme.png │ │ │ └── screenshot.png │ │ ├── theme.toml │ │ ├── assets │ │ │ ├── search-data.json │ │ │ └── js │ │ │ │ └── search.js │ │ ├── LICENSE │ │ └── README.md │ └── update.sh ├── content │ ├── _includes │ │ ├── _index.md │ │ └── include-page.md │ ├── usage │ │ ├── _index.md │ │ ├── overview.md │ │ ├── getting-started.md │ │ └── crd-specs.md │ └── _index.md ├── archetypes │ └── default.md ├── config.yaml ├── data │ └── menu │ │ └── extra.yaml ├── README.md ├── .env.example └── docker-compose.yaml ├── .dockerignore ├── .gitignore ├── generate.go ├── charts ├── cr.yaml ├── dockhand-secrets-operator-crd │ ├── Chart.yaml │ ├── README.md │ └── templates │ │ └── crd │ │ ├── secret-crd.yaml │ │ └── profile-crd.yaml └── dockhand-secrets-operator │ ├── Chart.yaml │ ├── templates │ ├── webhook │ │ ├── service.yaml │ │ ├── deployment.yaml │ │ ├── mutating-webhook.yaml │ │ └── rbac.yaml │ ├── controller │ │ ├── deployment.yaml │ │ └── rbac.yaml │ └── _helpers.tpl │ ├── README.md │ └── values.yaml ├── .yamlfmt ├── .github ├── dependabot.yml └── workflows │ ├── pre-commit.yml │ ├── helm.yaml │ └── docker.yaml ├── .yamllint ├── netlify.toml ├── scripts └── boilerplate.go.txt ├── Dockerfile ├── pkg ├── apis │ └── dhs.dockhand.dev │ │ ├── v1alpha2 │ │ ├── doc.go │ │ ├── zz_generated_list_types.go │ │ ├── zz_generated_register.go │ │ └── types.go │ │ └── zz_generated_register.go ├── codegen │ ├── cleanup │ │ └── main.go │ └── main.go ├── common │ ├── common.go │ └── tls.go └── generated │ └── controllers │ └── dhs.dockhand.dev │ ├── interface.go │ ├── v1alpha2 │ ├── profile.go │ ├── interface.go │ └── secret.go │ └── factory.go ├── main.go ├── Makefile ├── .pre-commit-config.yaml ├── cmd ├── root.go ├── operator.go └── server.go ├── README.md └── go.mod /docs/.gitignore: -------------------------------------------------------------------------------- 1 | /.env 2 | /public 3 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/VERSION: -------------------------------------------------------------------------------- 1 | v0.17.0 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/taxonomy/list.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/taxonomy/taxonomy.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/content/_includes/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | GeekdocHidden: true 3 | --- 4 | -------------------------------------------------------------------------------- /docs/content/usage/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Usage 3 | weight: -20 4 | --- 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/custom.css: -------------------------------------------------------------------------------- 1 | /* You can add custom styles here. */ 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/data/assets-static.json: -------------------------------------------------------------------------------- 1 | { 2 | "custom.css": "custom.css" 3 | } 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | /bin 3 | /release 4 | /dockhand-secrets-operator 5 | /local-test 6 | /charts 7 | .idea 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /release 2 | .idea 3 | /local-test* 4 | /remote-test* 5 | /bin 6 | ./dockhand-secrets-operator 7 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/head/custom.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | --- 6 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/archetypes/posts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | --- 5 | -------------------------------------------------------------------------------- /generate.go: -------------------------------------------------------------------------------- 1 | //go:generate go run ./pkg/codegen/cleanup/main.go 2 | //go:generate go run ./pkg/codegen/main.go 3 | 4 | package main 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/images/tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/images/tn.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/head/favicons.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/config.yaml: -------------------------------------------------------------------------------- 1 | baseURL: https://secrets-operator.dockhand.dev/ 2 | languageCode: en-us 3 | title: dockhand-secrets-operator 4 | theme: hugo-geekdocs 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/images/readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/images/readme.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/js/clipboard-loader-f0b5fbd5f6.min.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded",function(n){new ClipboardJS(".clip")}); -------------------------------------------------------------------------------- /charts/cr.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/helm/chart-releaser#config-file 2 | pages-branch: gh-pages 3 | pages-index-path: charts/index.yaml 4 | skip-existing: true 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/images/screenshot.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/hint.html: -------------------------------------------------------------------------------- 1 |
2 | {{ .Inner | $.Page.RenderString }} 3 |
4 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/js/katex-loader-3cfedeea38.min.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded",function(){renderMathInElement(document.body)}); -------------------------------------------------------------------------------- /docs/data/menu/extra.yaml: -------------------------------------------------------------------------------- 1 | header: 2 | - name: GitHub 3 | ref: https://github.com/boxboat/dockhand-secrets-operator 4 | icon: gdoc_github 5 | external: true 6 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/favicon.ico -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/Metropolis.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/Metropolis.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/mstile-70x70.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/GeekdocIcons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/GeekdocIcons.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/GeekdocIcons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/GeekdocIcons.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/Metropolis.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/Metropolis.woff2 -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Docs 2 | 3 | ## Build Locally 4 | 5 | - `docker compose up` 6 | - To change Port or switch to Polling FS Watcher arg, copy `.env.example` to `.env` and modify `.env` 7 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/mstile-144x144.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/mstile-310x150.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/mstile-310x310.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Bold.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationMono.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationMono.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationMono.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationMono.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationSans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationSans.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationSans.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationSans.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/icon.html: -------------------------------------------------------------------------------- 1 | {{ $id := .Get 0 }} 2 | 3 | {{- with $id -}} 4 | 5 | {{- end -}} 6 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_AMS-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_AMS-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_AMS-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_AMS-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_AMS-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_AMS-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Bold.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Italic.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-Italic.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size1-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size1-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size2-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size2-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size3-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size3-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size4-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size4-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/archetypes/docs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ .Name | humanize | title }}" 3 | weight: 1 4 | # geekdocFlatSection: false 5 | # geekdocToc: 6 6 | # geekdocHidden: false 7 | --- 8 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-BoldItalic.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-BoldItalic.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Bold.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Script-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Script-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Script-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Script-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size1-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size1-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size1-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size1-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size2-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size2-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size2-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size2-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size3-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size3-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size3-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size3-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size4-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size4-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Size4-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationSans-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationSans-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationSans-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationSans-Bold.woff2 -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator-crd/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: dockhand-secrets-operator-crd 3 | description: A Helm chart to install the dockhand-secrets-operator CRDs 4 | version: 1.1.7 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Bold.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Fraktur-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-BoldItalic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Main-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-BoldItalic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Math-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Italic.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Script-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Script-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Typewriter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Typewriter-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationSans-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationSans-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationSans-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Regular.ttf -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_SansSerif-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Typewriter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Typewriter-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Typewriter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Typewriter-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationSans-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationSans-BoldItalic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/KaTeX_Caligraphic-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/fonts/LiberationSans-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxboat/dockhand-secrets-operator/HEAD/docs/themes/hugo-geekdocs/static/fonts/LiberationSans-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/_default/_markup/render-image.html: -------------------------------------------------------------------------------- 1 | {{ .Text }} 2 | {{- /* Drop trailing newlines */ -}} 3 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/svg-icon-symbols.html: -------------------------------------------------------------------------------- 1 | {{ range resources.Match "sprites/*.svg" }} 2 | {{ printf "" . | safeHTML }} 3 | {{ .Content | safeHTML }} 4 | {{ end }} 5 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: dockhand-secrets-operator 3 | description: A Helm chart to install the dockhand-secrets-operator 4 | type: application 5 | version: 0.5.5 6 | appVersion: v1.1.7 7 | -------------------------------------------------------------------------------- /docs/.env.example: -------------------------------------------------------------------------------- 1 | # defaults to "--watch" which uses OS native filesystem watching 2 | # set to "--poll=1s" in order to use polling filesystem watching 3 | POLL_ARG="--watch" 4 | 5 | # change in order to listen on different port 6 | PORT=1313 7 | -------------------------------------------------------------------------------- /docs/content/_includes/include-page.md: -------------------------------------------------------------------------------- 1 | _**Example page include**_ 2 | 3 | {{< hint info >}} 4 | **Example Shortcode**\ 5 | Shortcode used in an include page. 6 | {{< /hint >}} 7 | 8 | | Head 1 | Head 2 | Head 3 | 9 | | ------ | ------ | ------ | 10 | | 1 | 2 | 3 | 11 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/columns.html: -------------------------------------------------------------------------------- 1 |
2 | {{ range split .Inner "<--->" }} 3 |
4 | {{ . | $.Page.RenderString }} 5 |
6 | {{ end }} 7 |
8 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/toc.html: -------------------------------------------------------------------------------- 1 | {{ $tocLevels := default (default 6 .Site.Params.GeekdocToC) .Page.Params.GeekdocToC }} 2 | 3 | {{ if and $tocLevels .Page.TableOfContents }} 4 |
{{ .Page.TableOfContents }}
5 | {{ end }} 6 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/_default/_markup/render-link.html: -------------------------------------------------------------------------------- 1 | {{- $raw := or (hasPrefix .Text "{{ .Text | safeHTML }} 3 | {{- /* Drop trailing newlines */ -}} 4 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/_default/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ partial "page-header" . }} 3 |
4 |

{{ partial "title" . }}

5 | {{ partial "content" . }} 6 |
7 | {{ end }} 8 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ partial "page-header" . }} 3 | 4 |
5 |

{{ partial "title" . }}

6 | {{ partial "content" . }} 7 |
8 | {{ end }} 9 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2f333e 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.yamlfmt: -------------------------------------------------------------------------------- 1 | gitignore_excludes: true 2 | doublestar: true 3 | exclude: 4 | - "charts/**/*.yaml" 5 | - "test/data/crds/*.yaml" 6 | # this next one is generated 7 | - "config/rbac/role.yaml" 8 | - "config/crd/bases/*.yaml" 9 | formatter: 10 | type: basic 11 | retain_line_breaks: true 12 | max_line_length: 78 13 | 14 | # vim: set ft=yaml : 15 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/title.html: -------------------------------------------------------------------------------- 1 | {{ $title := "" }} 2 | 3 | {{ if .Title }} 4 | {{ $title = .Title }} 5 | {{ else if and .IsSection .File }} 6 | {{ $title = path.Base .File.Dir | humanize | title }} 7 | {{ else if and .IsPage .File }} 8 | {{ $title = .File.BaseFileName | humanize | title }} 9 | {{ end }} 10 | 11 | {{ return $title }} 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | - package-ecosystem: "docker" 12 | directory: "/" 13 | schedule: 14 | interval: "weekly" 15 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | extends: default 2 | 3 | ignore: 4 | # AFAICT, these are all generated 5 | - config/ 6 | - charts/ 7 | - testdata/crds/ 8 | 9 | rules: 10 | document-start: false 11 | colons: 12 | max-spaces-before: 0 13 | max-spaces-after: -1 14 | line-length: false 15 | 16 | indentation: 17 | indent-sequences: consistent 18 | 19 | # vim: set ft=yaml : 20 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/js/mermaid-loader-1bd1515cbf.min.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded",function(e){var a=localStorage.getItem(THEME),t=window.matchMedia("(prefers-color-scheme: dark)");let r="#ececff",o=!1;(a===DARK_MODE||a===AUTO_MODE&&t.matches)&&(r="#6C617E",o=!0),mermaid.initialize({flowchart:{useMaxWidth:!0},theme:"base",themeVariables:{darkMode:o,primaryColor:r}})}); -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/templates/webhook/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook 5 | spec: 6 | type: ClusterIP 7 | selector: 8 | app.kubernetes.io/name: {{ include "dockhand-secrets-operator.name" . }}-webhook 9 | ports: 10 | - protocol: TCP 11 | port: 443 12 | targetPort: https 13 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/content.html: -------------------------------------------------------------------------------- 1 | {{- $content := .Content -}} 2 | {{- $content = $content | replaceRE `` `` | safeHTML -}} 3 | {{- $content = $content | replaceRE `((?:.|\n)+?
)` `
${1}
` | safeHTML -}} 4 | {{- $content -}} 5 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "docs" 3 | publish = "public" 4 | command = "hugo --gc --minify" 5 | 6 | [build.environment] 7 | HUGO_VERSION = "0.85.0" 8 | 9 | [context.deploy-preview] # merge-requests 10 | command = "hugo --gc --minify --buildDrafts --buildFuture -b $DEPLOY_PRIME_URL" 11 | 12 | [context.branch-deploy] # branches 13 | command = "hugo --gc --minify --buildDrafts --buildFuture -b $DEPLOY_PRIME_URL" 14 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/tab.html: -------------------------------------------------------------------------------- 1 | {{ if .Parent }} 2 | {{ $name := .Get 0 }} 3 | {{ $group := printf "tabs-%s" (.Parent.Get 0) }} 4 | 5 | {{ if not (.Parent.Scratch.Get $group) }} 6 | {{ .Parent.Scratch.Set $group slice }} 7 | {{ end }} 8 | 9 | {{ .Parent.Scratch.Add $group (dict "Name" $name "Content" .Inner) }} 10 | {{ else }} 11 | {{ errorf "%q: 'tab' shortcode must be inside 'tabs' shortcode" .Page.Path }} 12 | {{ end}} 13 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/theme.toml: -------------------------------------------------------------------------------- 1 | name = "Geekdoc" 2 | license = "MIT" 3 | licenselink = "https://github.com/thegeeklab/hugo-geekdoc/blob/main/LICENSE" 4 | description = "Hugo theme made for documentation" 5 | homepage = "https://geekdocs.de/" 6 | demosite = "https://geekdocs.de/" 7 | tags = ["docs", "documentation", "responsive", "simple"] 8 | min_version = "0.83.0" 9 | 10 | [author] 11 | name = "Robert Kaussow" 12 | homepage = "https://thegeeklab.de/" 13 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator-crd/README.md: -------------------------------------------------------------------------------- 1 | # dockhand-secrets-operator-crd 2 | Installs the CRDs required for the [dockhand-secrets-operator](https://github.com/boxboat/dockhand-secrets-operator) 3 | 4 | Read the [docs](https://secrets-operator.dockhand.dev) 5 | 6 | ## Install Instructions 7 | ``` 8 | helm repo add dso https://boxboat.github.io/dockhand-secrets-operator/charts 9 | helm repo update 10 | helm install --namespace dockhand-secrets-operator dso/dockhand-secrets-operator-crd 11 | ``` 12 | -------------------------------------------------------------------------------- /docs/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | hugo: 5 | image: jojomi/hugo:0.85.0 6 | container_name: dockhand-secrets-operator-docs 7 | volumes: 8 | - ./:/src 9 | entrypoint: 10 | - hugo 11 | command: 12 | - serve 13 | - --baseURL=http://localhost:${PORT:-1313}/ 14 | - --bind=0.0.0.0 15 | - --buildDrafts 16 | - --port=${PORT:-1313} 17 | - "${POLL_ARG:---watch}" 18 | ports: 19 | - "${PORT:-1313}:${PORT:-1313}" 20 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/assets/search-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | {{ range $index, $page := (where .Site.Pages "Params.GeekdocProtected" "ne" true) }} 3 | {{ if ne $index 0 }},{{ end }} 4 | { 5 | "id": {{ $index }}, 6 | "href": "{{ $page.RelPermalink }}", 7 | "title": {{ (partial "title" $page) | jsonify }}, 8 | "parent": {{ with $page.Parent }}{{ (partial "title" .) | jsonify }}{{ else }}""{{ end }}, 9 | "content": {{ $page.Plain | jsonify }} 10 | } 11 | {{ end }} 12 | ] 13 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/mermaid.html: -------------------------------------------------------------------------------- 1 | {{ if not (.Page.Scratch.Get "mermaid") }} 2 | 3 | 4 | 5 | {{ .Page.Scratch.Set "mermaid" true }} 6 | {{ end }} 7 | 8 |
 9 |   {{- .Inner -}}
10 | 
11 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/print-f79fc3e5d7.min.css: -------------------------------------------------------------------------------- 1 | @media print{.editpage,.gdoc-footer .container span:not(:first-child),.gdoc-nav{display:none}.gdoc-footer{border-top:1px solid #dee2e6}.gdoc-markdown pre{white-space:pre-wrap;overflow-wrap:break-word}.chroma code{border:1px solid #dee2e6;padding:.5rem!important;font-weight:400!important}.gdoc-markdown code{font-weight:700}a,a:visited{color:inherit!important;text-decoration:none!important}.gdoc-toc{flex:none}.gdoc-toc nav{position:relative;width:auto}.wrapper{display:block}.wrapper main{display:block}} -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/search.html: -------------------------------------------------------------------------------- 1 | {{ if default true .Site.Params.GeekdocSearch }} 2 | 9 | {{ end }} 10 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/js/groupBy-174feb11c7.min.js: -------------------------------------------------------------------------------- 1 | const groupBy=(r,...e)=>{let t=r.map(t=>e.map(e=>e(t))),a={};return t.forEach((e,t)=>{t=(_simpleAt(a,e)||[]).concat([r[t]]);_simpleSet(a,e,t)}),a},_isPlainObject=e=>null!=e&&"object"==typeof e&&e.constructor==Object,_parsePath=e=>Array.isArray(e)?e:`${e}`.split("."),_simpleAt=(e,t)=>_parsePath(t).reduce((e,t)=>null!=e&&e.hasOwnProperty(t)?e[t]:void 0,e),_simpleSet=(e,t,s)=>_parsePath(t).reduce((e,t,r,a)=>{a=r===a.length-1;return e.hasOwnProperty(t)&&(a||_isPlainObject(e[t]))||(e[t]={}),a?e[t]=s:e[t]},e); -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/expand.html: -------------------------------------------------------------------------------- 1 | {{ $id := substr (sha1 .Inner) 0 8 }} 2 |
3 | 7 | 8 |
9 | {{ .Inner | $.Page.RenderString }} 10 |
11 |
12 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/README.md: -------------------------------------------------------------------------------- 1 | # dockhand-secrets-operator 2 | Installs the [dockhand-secrets-operator](https://github.com/boxboat/dockhand-secrets-operator) 3 | 4 | Read the [docs](https://secrets-operator.dockhand.dev) 5 | 6 | 7 | ## Install Instructions 8 | ``` 9 | helm repo add dso https://boxboat.github.io/dockhand-secrets-operator/charts 10 | helm repo update 11 | helm install --namespace dockhand-secrets-operator dso/dockhand-secrets-operator-crd 12 | helm install --namespace dockhand-secrets-operator dso/dockhand-secrets-operator 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/favicon/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/favicon/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#2f333e", 17 | "background_color": "#2f333e", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/head/meta.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ $description := default (default .Site.Title .Site.Params.description) (default .Summary .Description) }} 6 | {{ $keywords := default .Site.Params.Keywords .Keywords }} 7 | 8 | {{ with $description }} 9 | 10 | {{ end }} 11 | {{ with $keywords }} 12 | 13 | {{ end }} 14 | -------------------------------------------------------------------------------- /docs/themes/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | cd "$(dirname "$0")" 4 | 5 | usage () { 6 | echo "usage: $0 versionNumber" >&2 7 | echo " get versionNumber from:" 8 | echo " https://github.com/thegeeklab/hugo-geekdoc/releases" 9 | } 10 | 11 | if [ "$#" -ne 1 ]; then 12 | usage && exit 1 13 | elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 14 | usage && exit 0 15 | fi 16 | 17 | version="$1" 18 | 19 | rm -rf hugo-geekdocs 20 | mkdir hugo-geekdocs 21 | curl -SsL "https://github.com/thegeeklab/hugo-geekdoc/releases/download/$version/hugo-geekdoc.tar.gz" \ 22 | | tar -xzC hugo-geekdocs 23 | -------------------------------------------------------------------------------- /scripts/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © YEAR BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: testing 2 | 3 | on: 4 | pull_request: 5 | # push: 6 | # branches: '**' 7 | 8 | jobs: 9 | pre-commit: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v5 13 | - uses: actions/setup-go@v6 14 | with: 15 | go-version-file: 'go.mod' 16 | - name: Install goimports 17 | run: go install golang.org/x/tools/cmd/goimports@latest 18 | - uses: actions/setup-python@v6 19 | 20 | # linting 21 | - uses: pre-commit/action@v3.0.1 22 | 23 | # ...and unit tests 24 | - name: Run tests 25 | run: make test 26 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/include.html: -------------------------------------------------------------------------------- 1 | {{ $file := .Get "file" }} 2 | {{ $page := .Site.GetPage $file }} 3 | {{ $type := .Get "type" }} 4 | {{ $language := .Get "language" }} 5 | {{ $options :=.Get "options" }} 6 | 7 |
8 | {{- if (.Get "language") -}} 9 | {{- highlight ($file | readFile) $language (default "linenos=table" $options) -}} 10 | {{- else if eq $type "html" -}} 11 | {{- $file | readFile | safeHTML -}} 12 | {{- else if eq $type "page" -}} 13 | {{- with $page }}{{ .Content }}{{ end -}} 14 | {{- else -}} 15 | {{- $file | readFile | $.Page.RenderString -}} 16 | {{- end -}} 17 |
18 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/tabs.html: -------------------------------------------------------------------------------- 1 | {{ if .Inner }}{{ end }} 2 | {{ $id := .Get 0 }} 3 | {{ $group := printf "tabs-%s" $id }} 4 | 5 |
6 | {{ range $index, $tab := .Scratch.Get $group }} 7 | 9 | 12 |
13 | {{ .Content | $.Page.RenderString }} 14 |
15 | {{ end }} 16 |
17 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/button.html: -------------------------------------------------------------------------------- 1 | {{ $ref := "" }} 2 | {{ $target := "" }} 3 | {{ $size := default "regular" (.Get "size" | lower) }} 4 | 5 | {{ if not (in (slice "regular" "large") $size) }} 6 | {{ $size = "regular" }} 7 | {{ end }} 8 | 9 | {{ with .Get "href" }} 10 | {{ $ref = . }} 11 | {{ $target = "_blank" }} 12 | {{ end }} 13 | 14 | {{ with .Get "relref" }} 15 | {{ $ref = relref $ . }} 16 | {{ end }} 17 | 18 | 19 | 20 | {{ $.Inner }} 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/menu.html: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VERSION=master 2 | ARG GO_VERSION=1.24.6 3 | 4 | FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION}-alpine AS build 5 | 6 | RUN apk --no-cache add make ca-certificates 7 | RUN adduser -D dockhand 8 | WORKDIR /src 9 | COPY go.mod go.sum /src/ 10 | RUN go mod download 11 | COPY . /src/ 12 | ARG TARGETOS 13 | ARG TARGETARCH 14 | ARG VERSION 15 | RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} VERSION=${VERSION} make build 16 | USER dockhand 17 | ENTRYPOINT ["/src/bin/dockhand-secrets-operator"] 18 | 19 | FROM gcr.io/distroless/static AS release 20 | 21 | COPY --from=build /etc/passwd /etc/group /etc/ 22 | COPY --from=build /src/bin/dockhand-secrets-operator /bin/dockhand-secrets-operator 23 | USER dockhand 24 | ENTRYPOINT ["/bin/dockhand-secrets-operator"] 25 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/foot.html: -------------------------------------------------------------------------------- 1 | {{ if default true .Site.Params.GeekdocSearch }} 2 | {{ .Scratch.Set "geekdocSearchConfig" .Site.Params.GeekdocSearchConfig }} 3 | 4 | {{ $searchJSFile := printf "js/%s.search.js" .Language.Lang }} 5 | {{ $searchJS := resources.Get "js/search.js" | resources.ExecuteAsTemplate $searchJSFile . | resources.Minify | fingerprint }} 6 | 7 | {{ end }} 8 | 9 | {{ if default true .Site.Params.GeekdocAnchorCopy }} 10 | 11 | 12 | {{ end }} 13 | -------------------------------------------------------------------------------- /pkg/apis/dhs.dockhand.dev/v1alpha2/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | // Code generated by main. DO NOT EDIT. 17 | 18 | // +k8s:deepcopy-gen=package 19 | // +groupName=dhs.dockhand.dev 20 | package v1alpha2 21 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/katex.html: -------------------------------------------------------------------------------- 1 | {{ if not (.Page.Scratch.Get "katex") }} 2 | 3 | 4 | 5 | 6 | 7 | {{ .Page.Scratch.Set "katex" true }} 8 | {{ end }} 9 | 10 | 11 | {{ cond (in .Params "display") "\\[" "\\(" -}} 12 | {{- trim .Inner "\n" -}} 13 | {{- cond (in .Params "display") "\\]" "\\)" }} 14 | 15 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/posts/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 |

{{ .Title }}

5 | 14 |
15 |
16 | {{ partial "content" . }} 17 |
18 |
19 | {{ end }} 20 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/js/darkmode-ce906ea916.min.js: -------------------------------------------------------------------------------- 1 | const DARK_MODE="dark",LIGHT_MODE="light",AUTO_MODE="auto",THEME="hugo-geekdoc",TOGGLE_MODES=[AUTO_MODE,DARK_MODE,LIGHT_MODE];function toggle(e=[],t){return current=e.indexOf(t),max=e.length-1,next=0,current{const t=document.getElementById("gdoc-dark-mode");t.onclick=function(){var e=localStorage.getItem(THEME),e=toggle(TOGGLE_MODES,e);localStorage.setItem(THEME,TOGGLE_MODES[e]),applyTheme(!1)}}); -------------------------------------------------------------------------------- /pkg/apis/dhs.dockhand.dev/zz_generated_register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | // Code generated by main. DO NOT EDIT. 17 | 18 | package dhs 19 | 20 | const ( 21 | // Package-wide consts from generator "zz_generated_register". 22 | GroupName = "dhs.dockhand.dev" 23 | ) 24 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/_default/_markup/render-heading.html: -------------------------------------------------------------------------------- 1 | {{- $showAnchor := (and (default true .Page.Params.GeekdocAnchor) (default true .Page.Site.Params.GeekdocAnchor)) -}} 2 | 3 | {{- if $showAnchor -}} 4 |
5 | 6 | {{ .Text | safeHTML }} 7 | 8 | 9 | 10 | 11 |
12 | {{- else -}} 13 |
14 | 15 | {{ .Text | safeHTML }} 16 | 17 |
18 | {{- end -}} 19 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 BoxBoat engineering@boxboat.com 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package main 15 | 16 | import ( 17 | "github.com/boxboat/dockhand-secrets-operator/cmd" 18 | ) 19 | 20 | // Version of webhook defined by Makefile. 21 | var Version = "undefined" 22 | 23 | func main() { 24 | cmd.Execute(Version) 25 | } 26 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/values.yaml: -------------------------------------------------------------------------------- 1 | 2 | # set allowCrossNamespace to true for single tenant cross namespace Profile reference 3 | # see https://secrets-operator.dockhand.dev/usage/core-concepts/ 4 | allowCrossNamespace: false 5 | 6 | controller: 7 | rbac: 8 | serviceAccount: 9 | # controller.rbac.serviceAccount.annotations -- Additional Service Account annotations. 10 | annotations: {} 11 | replicas: 1 12 | image: 13 | pullPolicy: IfNotPresent 14 | repository: boxboat/dockhand-secrets-operator 15 | tag: v1.1.7 16 | resources: {} 17 | 18 | webhook: 19 | rbac: 20 | serviceAccount: 21 | # webhook.rbac.serviceAccount.annotations -- Additional Service Account annotations. 22 | annotations: {} 23 | replicas: 1 24 | image: 25 | pullPolicy: IfNotPresent 26 | repository: boxboat/dockhand-secrets-operator 27 | tag: v1.1.7 28 | resources: {} 29 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/data/assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "custom.css": "custom.css", 3 | "js/auto-render.min.js": "js/auto-render-e6e57901eb.min.js", 4 | "js/clipboard-loader.min.js": "js/clipboard-loader-f0b5fbd5f6.min.js", 5 | "js/clipboard.min.js": "js/clipboard-27784b7376.min.js", 6 | "js/darkmode.min.js": "js/darkmode-ce906ea916.min.js", 7 | "js/flexsearch.min.js": "js/flexsearch-e54a90f706.min.js", 8 | "js/groupBy.min.js": "js/groupBy-174feb11c7.min.js", 9 | "js/katex-loader.min.js": "js/katex-loader-3cfedeea38.min.js", 10 | "js/katex.min.js": "js/katex-b7063e58c5.min.js", 11 | "js/mermaid-loader.min.js": "js/mermaid-loader-1bd1515cbf.min.js", 12 | "js/mermaid.min.js": "js/mermaid-1fc9ef3e82.min.js", 13 | "katex.min.css": "katex-38042a7abd.min.css", 14 | "main.min.css": "main-0c0de99286.min.css", 15 | "mobile.min.css": "mobile-c344439d04.min.css", 16 | "print.min.css": "print-f79fc3e5d7.min.css" 17 | } -------------------------------------------------------------------------------- /pkg/codegen/cleanup/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "os" 21 | 22 | "github.com/rancher/wrangler/v3/pkg/cleanup" 23 | "github.com/sirupsen/logrus" 24 | ) 25 | 26 | func main() { 27 | if err := cleanup.Cleanup("./pkg/apis"); err != nil { 28 | logrus.Fatal(err) 29 | } 30 | if err := os.RemoveAll("./pkg/generated"); err != nil { 31 | logrus.Fatal(err) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/helm.yaml: -------------------------------------------------------------------------------- 1 | # based on: https://github.com/helm/charts-repo-actions-demo/blob/main/.github/workflows/release.yaml 2 | name: helm 3 | 4 | on: 5 | push: 6 | paths: 7 | - 'charts/**' 8 | branches: 9 | - master 10 | 11 | jobs: 12 | helm: 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: write 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v5 19 | with: 20 | fetch-depth: 0 21 | 22 | - name: Configure Git 23 | run: | 24 | git config user.name "$GITHUB_ACTOR" 25 | git config user.email "$GITHUB_ACTOR@users.noreply.github.com" 26 | 27 | - name: Set up Helm 28 | uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 29 | with: 30 | version: v3.11.2 31 | 32 | - name: Run chart-releaser 33 | uses: helm/chart-releaser-action@cae68fefc6b5f367a0275617c9f83181ba54714f 34 | with: 35 | charts_dir: charts 36 | config: charts/cr.yaml 37 | env: 38 | CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 39 | -------------------------------------------------------------------------------- /pkg/common/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package common 18 | 19 | import ( 20 | "os" 21 | 22 | log "github.com/sirupsen/logrus" 23 | ) 24 | 25 | var ( 26 | // Log for global use 27 | Log = log.New() 28 | ) 29 | 30 | // ExitIfError will generically handle an error by logging its contents 31 | // and exiting with a return code of 1. 32 | func ExitIfError(err error) { 33 | if err != nil { 34 | Log.Errorf("%v", err) 35 | os.Exit(1) 36 | } 37 | } 38 | 39 | func LogIfError(err error) { 40 | if err != nil { 41 | Log.Warnf("%v", err) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Robert Kaussow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/menu-extra.html: -------------------------------------------------------------------------------- 1 | {{ $current := .current }} 2 | {{ template "menu-extra" dict "sect" .source "current" $current "site" $current.Site "target" .target }} 3 | 4 | 5 | {{ define "menu-extra" }} 6 | {{ $current := .current }} 7 | {{ $site := .site }} 8 | {{ $target := .target }} 9 | {{ $sect := .sect }} 10 | 11 | {{ range sort (default (seq 0) $sect) "weight" }} 12 | {{ if isset . "ref" }} 13 | {{ $this := $site.GetPage .ref }} 14 | {{ $isCurrent := eq $current $this }} 15 | {{ $icon := default false .icon }} 16 | 17 | {{ if not .icon }} 18 | {{ errorf "Missing 'icon' attribute in data file for '%s' menu item '%s'" $target .name }} 19 | {{ end }} 20 | 21 | {{ if eq $target "header" }} 22 | 23 | 24 | {{ .name }} 25 | 26 | 27 | 28 | {{ end }} 29 | {{ end }} 30 | {{ end }} 31 | {{ end }} 32 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/mobile-c344439d04.min.css: -------------------------------------------------------------------------------- 1 | @media screen and (max-width:39rem){.gdoc-nav{margin-left:-16rem;font-size:16px}.gdoc-nav__control{display:inline-block}.gdoc-header .icon{width:1.5rem;height:1.5rem}.gdoc-brand{font-size:1.5rem}.gdoc-brand__img{display:none}.gdoc-menu-header__items{display:none}.gdoc-menu-header__control{display:inline-block}.gdoc-error{padding:6rem 1rem}.gdoc-error .icon{width:6rem;height:6rem}.gdoc-error__message{padding-left:2rem}.gdoc-error__line{padding:.25rem 0}.gdoc-error__title{font-size:2rem}.gdoc-page__header .breadcrumb,.hidden-mobile{display:none}.gdoc-footer__item--row{width:100%}#menu-control:checked~main .gdoc-nav nav,#menu-control:checked~main .gdoc-page{transform:translateX(16rem)}#menu-control:checked~main .gdoc-page{opacity:.25}#menu-control:checked~.gdoc-header .gdoc-nav__control .icon.gdoc_menu{display:none}#menu-control:checked~.gdoc-header .gdoc-nav__control .icon.gdoc_arrow_back{display:inline-block}#menu-header-control:checked~.gdoc-header .gdoc-brand__title{display:none}#menu-header-control:checked~.gdoc-header .gdoc-menu-header__items{display:inline-block}#menu-header-control:checked~.gdoc-header .gdoc-menu-header__control .icon.gdoc_keyborad_arrow_left{display:none}} -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/posts/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ range .Paginator.Pages }} 3 |
4 |
5 |

{{ .Title }}

6 | 15 |
16 |
17 | {{ .Summary }} 18 |
19 | {{ if .Truncated }} 20 |
21 | Read full post 22 |
23 | {{ end }} 24 |
25 | {{ end }} 26 | {{ end }} 27 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/toc-tree.html: -------------------------------------------------------------------------------- 1 | {{ $tocLevels := default (default 6 .Site.Params.GeekdocToC) .Page.Params.GeekdocToC }} 2 | 3 | {{ if $tocLevels }} 4 |
5 | {{ template "toc-tree" dict "sect" .Page.Pages }} 6 |
7 | {{ end }} 8 | 9 | 10 | {{ define "toc-tree" }} 11 | 33 | {{ end }} 34 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/shortcodes/img.html: -------------------------------------------------------------------------------- 1 | {{ $source := ($.Page.Resources.ByType "image").GetMatch (printf "%s" (.Get "name")) }} 2 | {{ $customAlt := .Get "alt" }} 3 | {{ $customSize := .Get "size" }} 4 | {{ $lazyLoad := default (default true $.Site.Params.GeekdocImageLazyLoading) (.Get "lazy") }} 5 | 6 | {{ with $source }} 7 | {{ $caption := default .Title $customAlt }} 8 | 9 | {{ $tiny := (.Resize "320x").RelPermalink }} 10 | {{ $small := (.Resize "600x").RelPermalink }} 11 | {{ $medium := (.Resize "1200x").RelPermalink }} 12 | {{ $large := (.Resize "1800x").RelPermalink }} 13 | 14 | {{ $size := dict "tiny" $tiny "small" $small "medium" $medium "large" $large }} 15 | 16 |
17 |
18 | 19 | 20 | 21 | {{ $caption }} 22 | 23 | 24 | {{ with $caption -}} 25 |
{{ . }}{{ with $source.Params.credits }} ({{ . | $.Page.RenderString }}){{ end }}
26 | {{- end }} 27 |
28 |
29 | {{ end }} 30 | -------------------------------------------------------------------------------- /pkg/generated/controllers/dhs.dockhand.dev/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | // Code generated by main. DO NOT EDIT. 17 | 18 | package dhs 19 | 20 | import ( 21 | v1alpha2 "github.com/boxboat/dockhand-secrets-operator/pkg/generated/controllers/dhs.dockhand.dev/v1alpha2" 22 | "github.com/rancher/lasso/pkg/controller" 23 | ) 24 | 25 | type Interface interface { 26 | V1alpha2() v1alpha2.Interface 27 | } 28 | 29 | type group struct { 30 | controllerFactory controller.SharedControllerFactory 31 | } 32 | 33 | // New returns a new Interface. 34 | func New(controllerFactory controller.SharedControllerFactory) Interface { 35 | return &group{ 36 | controllerFactory: controllerFactory, 37 | } 38 | } 39 | 40 | func (g *group) V1alpha2() v1alpha2.Interface { 41 | return v1alpha2.New(g.controllerFactory) 42 | } 43 | -------------------------------------------------------------------------------- /pkg/generated/controllers/dhs.dockhand.dev/v1alpha2/profile.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | // Code generated by main. DO NOT EDIT. 17 | 18 | package v1alpha2 19 | 20 | import ( 21 | v1alpha2 "github.com/boxboat/dockhand-secrets-operator/pkg/apis/dhs.dockhand.dev/v1alpha2" 22 | "github.com/rancher/wrangler/v3/pkg/generic" 23 | ) 24 | 25 | // ProfileController interface for managing Profile resources. 26 | type ProfileController interface { 27 | generic.ControllerInterface[*v1alpha2.Profile, *v1alpha2.ProfileList] 28 | } 29 | 30 | // ProfileClient interface for managing Profile resources in Kubernetes. 31 | type ProfileClient interface { 32 | generic.ClientInterface[*v1alpha2.Profile, *v1alpha2.ProfileList] 33 | } 34 | 35 | // ProfileCache interface for retrieving Profile resources in memory. 36 | type ProfileCache interface { 37 | generic.CacheInterface[*v1alpha2.Profile] 38 | } 39 | -------------------------------------------------------------------------------- /pkg/codegen/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | dockhand "github.com/boxboat/dockhand-secrets-operator/pkg/apis/dhs.dockhand.dev/v1alpha2" 21 | controllergen "github.com/rancher/wrangler/v3/pkg/controller-gen" 22 | "github.com/rancher/wrangler/v3/pkg/controller-gen/args" 23 | 24 | // Ensure gvk gets loaded in wrangler/pkg/gvk cache 25 | _ "github.com/rancher/wrangler/v3/pkg/generated/controllers/apiextensions.k8s.io/v1" 26 | ) 27 | 28 | func main() { 29 | controllergen.Run(args.Options{ 30 | OutputPackage: "github.com/boxboat/dockhand-secrets-operator/pkg/generated", 31 | Boilerplate: "scripts/boilerplate.go.txt", 32 | Groups: map[string]args.Group{ 33 | "dhs.dockhand.dev": { 34 | Types: []interface{}{ 35 | dockhand.Secret{}, 36 | dockhand.Profile{}, 37 | }, 38 | GenerateTypes: true, 39 | }, 40 | }, 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ partial "head/meta" . }} 6 | {{ if not (eq .Kind "home") }}{{ partial "title" . }} | {{ end }}{{ .Site.Title }} 7 | 8 | {{ partial "head/favicons" . }} 9 | {{ partial "head/others" . }} 10 | {{ partial "head/custom" . }} 11 | 12 | 13 | 14 | {{ partial "svg-icon-symbols" . }} 15 | 16 |
17 | 18 | 19 | {{ $navEnabled := default true .Page.Params.GeekdocNav }} 20 | {{ partial "site-header" (dict "Root" . "MenuEnabled" $navEnabled) }} 21 | 22 |
23 | {{ if $navEnabled }} 24 | 27 | {{ end }} 28 | 29 |
30 | {{ template "main" . }} 31 | {{ partial "page-footer" . }} 32 |
33 |
34 | 35 | {{ partial "site-footer" . }} 36 |
37 | 38 | {{ partial "foot" . }} 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ partial "head/meta" . }} 6 | Lost? Don't worry 7 | 8 | {{ partial "head/favicons" . }} 9 | {{ partial "head/others" . }} 10 | 11 | 12 | 13 | {{ partial "svg-icon-symbols" . }} 14 | 15 |
16 | 17 | {{ partial "site-header" (dict "Root" . "MenuEnabled" false) }} 18 | 19 |
20 |
21 |
22 | 23 |
24 |
25 |
Lost?
26 |
Error 404
27 |
28 | Seems like what you are looking for can't be found. Don't worry we can 29 | bring you back to the homepage. 30 |
31 |
32 |
33 |
34 | 35 | {{ partial "site-footer" . }} 36 | 37 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/site-footer.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | Built with Hugo and 6 | 7 | 8 | {{ with .Site.Params.GeekdocLegalNotice }} 9 | 10 | Legal Notice 11 | 12 | {{ end }} 13 | {{ with .Site.Params.GeekdocPrivacyPolicy }} 14 | 15 | Privacy Policy 16 | 17 | {{ end }} 18 |
19 | {{ if (default true .Site.Params.GeekdocBackToTop) }} 20 |
21 | 22 | 23 | Back to top 24 | 25 | 26 |
27 | {{ end }} 28 |
29 |
30 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/templates/controller/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "dockhand-secrets-operator.name" . }}-controller 5 | labels: 6 | app.kubernetes.io/name: {{ include "dockhand-secrets-operator.name" . }}-controller 7 | {{- include "dockhand-secrets-operator.labels" . | nindent 4 }} 8 | spec: 9 | replicas: {{ .Values.controller.replicas }} 10 | selector: 11 | matchLabels: 12 | app.kubernetes.io/name: {{ include "dockhand-secrets-operator.name" . }}-controller 13 | template: 14 | metadata: 15 | labels: 16 | app.kubernetes.io/name: {{ include "dockhand-secrets-operator.name" . }}-controller 17 | spec: 18 | serviceAccountName: {{ include "dockhand-secrets-operator.name" . }}-controller-sa 19 | containers: 20 | - name: controller 21 | image: "{{ tpl .Values.controller.image.repository . }}:{{ tpl .Values.controller.image.tag . }}" 22 | imagePullPolicy: {{ .Values.controller.image.pullPolicy }} 23 | args: 24 | - controller 25 | - --namespace 26 | - {{ .Release.Namespace }} 27 | {{- if .Values.allowCrossNamespace }} 28 | - --allow-cross-namespace 29 | {{- end }} 30 | ports: 31 | - containerPort: 8443 32 | name: https 33 | resources: 34 | {{- if .Values.controller.resources }} 35 | {{- toYaml .Values.controller.resources | nindent 12 }} 36 | {{- end }} 37 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/head/others.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {{ with .OutputFormats.Get "rss" -}} 19 | {{ printf `` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }} 20 | {{ end -}} 21 | 22 | {{ if (default false $.Site.Params.GeekdocOverwriteHTMLBase) }} 23 | 24 | {{ end }} 25 | 26 | {{ printf "" "Made with Geekdoc theme https://github.com/thegeeklab/hugo-geekdoc" | safeHTML }} 27 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | .{{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "dockhand-secrets-operator.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "dockhand-secrets-operator.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "dockhand-secrets-operator.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | 34 | {{/* 35 | Common labels 36 | */}} 37 | {{- define "dockhand-secrets-operator.labels" -}} 38 | app.kubernetes.io/instance: {{ .Release.Name }} 39 | helm.sh/chart: {{ include "dockhand-secrets-operator.chart" . }} 40 | app.kubernetes.io/managed-by: {{ .Release.Service }} 41 | {{- if .Values.additionalLabels }} 42 | {{ toYaml .Values.additionalLabels }} 43 | {{- end -}} 44 | {{- end -}} 45 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/templates/webhook/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook 5 | labels: 6 | app.kubernetes.io/name: {{ include "dockhand-secrets-operator.name" . }}-webhook 7 | {{- include "dockhand-secrets-operator.labels" . | nindent 4 }} 8 | spec: 9 | replicas: {{ .Values.webhook.replicas }} 10 | selector: 11 | matchLabels: 12 | app.kubernetes.io/name: {{ include "dockhand-secrets-operator.name" . }}-webhook 13 | template: 14 | metadata: 15 | labels: 16 | app.kubernetes.io/name: {{ include "dockhand-secrets-operator.name" . }}-webhook 17 | spec: 18 | serviceAccountName: {{ include "dockhand-secrets-operator.name" . }}-webhook-sa 19 | containers: 20 | - name: webhook 21 | image: "{{ tpl .Values.webhook.image.repository . }}:{{ tpl .Values.webhook.image.tag . }}" 22 | imagePullPolicy: {{ .Values.webhook.image.pullPolicy }} 23 | args: 24 | - server 25 | - --name 26 | - {{ include "dockhand-secrets-operator.name" . }}-webhook 27 | - --namespace 28 | - {{ .Release.Namespace }} 29 | - --webhook-id 30 | - $(POD_NAME) 31 | env: 32 | - name: POD_NAME 33 | valueFrom: 34 | fieldRef: 35 | apiVersion: v1 36 | fieldPath: metadata.name 37 | ports: 38 | - containerPort: 8443 39 | name: https 40 | resources: 41 | {{- if .Values.webhook.resources }} 42 | {{- toYaml .Values.webhook.resources | nindent 12 }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /docs/content/usage/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | weight: -100 4 | --- 5 | 6 | ## What is the Dockhand Secrets Operator? 7 | 8 | Dockhand Secrets Operator is a Secrets Management Kubernetes Operator. 9 | 10 | ## Why Dockhand Secrets Operator? 11 | Creation of arbitrary Kubernetes Secrets for your application deployments should be declarative, repeatable, easy, secure and flexible. In an ideal world, your Kubernetes `Secrets` manifests would be stored in your git repository alongside your application deployment manifests - allowing for full GitOps. The obvious problem is then your secrets aren't secret anymore. 12 | 13 | `dockhand-secrets-operator` gives you the next best thing a `CustomResourceDefinition` - Dockhand `Secret` that has feature parity with a Kubernetes `Secret` manifest. The `Secret` feels like a regular `Secret` but provides a familiar Go templating syntax that will allow the operator to make your Kubernets `Secret` during your manifest deployment. 14 | 15 | `dockhand-secrets-operator` can also provide automatic rollover of `Deployments`, `DaemonSets` and `StatefulSets` - with the addition of a single `Label`. 16 | 17 | ## How it works 18 | `dockhand-secrets-operator` monitors the creation and update of Dockhand `Secret`, parses the spec and creates a corresponding Kubernetes `Secrets`. Optionally, with addition of a label on a `Deployment`, `StatefulSet` or `DaemonSet` the operator will also checksum the secret and insert a managed annotation, which will trigger an update in accordance with the update policy on each of those types. 19 | 20 | If you wish to have a fully automatic experience, you can enable a `syncInterval` on a per Dockhand `Secret` basis that will instruct the operator to poll your Secrets backend for changes. When a change is detected, the operator will rollout a new `Deployment`, `StatefulSet` or `DaemonSet`. 21 | -------------------------------------------------------------------------------- /docs/content/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dockhand Secrets Operator 3 | description: Secure Kubernetes Secrets Manager Integration 4 | geekdocNav: false 5 | geekdocAlign: center 6 | geekdocAnchor: false 7 | --- 8 | 9 | 10 | 11 | 12 | [![Build Status](https://img.shields.io/github/actions/workflow/status/boxboat/dockhand-secrets-operator/docker.yaml?master)](https://github.com/boxboat/dockhand-secrets-operator) 13 | [![GitHub release](https://img.shields.io/github/v/release/boxboat/dockhand-secrets-operator)](https://github.com/boxboat/dockhand-secrets-operator/releases/latest) 14 | [![GitHub contributors](https://img.shields.io/github/contributors/boxboat/dockhand-secrets-operator)](https://github.com/boxboat/dockhand-secrets-operator/graphs/contributors) 15 | [![License: APACHE](https://img.shields.io/github/license/boxboat/dockhand-secrets-operator)](https://github.com/boxboat/dockhand-secrets-operator/blob/main/LICENSE) 16 | 17 | 18 | 19 | Secrets management with full GitOps can be challenging in Kubernetes environments. Often engineers resort to manual secret creation, injection of secrets through scripts with the CI/CD tool or even worse just committing the secrets directly to git. 20 | 21 | The Dockhand Secrets Operator solves that problem by allowing you to make arbitrary secrets in a familiar way with only the secret bits stored in the backend(s) of your choice - AWS Secrets Manager, Azure Key Vault, GCP Secrets Manager or Vault. Secret references can be stored in git with your Helm chart or Kubernetes manifests. 22 | 23 | {{< button size="large" relref="usage/getting-started/" >}}Getting Started{{< /button >}} 24 | -------------------------------------------------------------------------------- /pkg/apis/dhs.dockhand.dev/v1alpha2/zz_generated_list_types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | // Code generated by main. DO NOT EDIT. 17 | 18 | // +k8s:deepcopy-gen=package 19 | // +groupName=dhs.dockhand.dev 20 | package v1alpha2 21 | 22 | import ( 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | ) 25 | 26 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 27 | 28 | // SecretList is a list of Secret resources 29 | type SecretList struct { 30 | metav1.TypeMeta `json:",inline"` 31 | metav1.ListMeta `json:"metadata"` 32 | 33 | Items []Secret `json:"items"` 34 | } 35 | 36 | func NewSecret(namespace, name string, obj Secret) *Secret { 37 | obj.APIVersion, obj.Kind = SchemeGroupVersion.WithKind("Secret").ToAPIVersionAndKind() 38 | obj.Name = name 39 | obj.Namespace = namespace 40 | return &obj 41 | } 42 | 43 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 44 | 45 | // ProfileList is a list of Profile resources 46 | type ProfileList struct { 47 | metav1.TypeMeta `json:",inline"` 48 | metav1.ListMeta `json:"metadata"` 49 | 50 | Items []Profile `json:"items"` 51 | } 52 | 53 | func NewProfile(namespace, name string, obj Profile) *Profile { 54 | obj.APIVersion, obj.Kind = SchemeGroupVersion.WithKind("Profile").ToAPIVersionAndKind() 55 | obj.Name = name 56 | obj.Namespace = namespace 57 | return &obj 58 | } 59 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | comma := , 2 | space := $(subst ,, ) 3 | 4 | BINARY ?= dockhand-secrets-operator 5 | VERSION ?= develop 6 | REGISTRY ?= docker.io 7 | DOCKER_TARGET ?= release 8 | PKGS ?= $(shell go list ./... | grep -v /vendor) 9 | DEBUG ?= false 10 | PROGRESS ?= plain 11 | GOOS ?= $(shell go env GOOS) 12 | GOARCH ?= $(shell go env GOARCH) 13 | OSES ?= linux darwin windows 14 | ARCHES ?= amd64 arm64 15 | PLATFORM_FILTERS ?= windows-arm64 16 | DOCKER_PLATFORM_FILTERS ?= windows/% darwin/% 17 | RELEASE_TARGET_FILTERS ?= $(foreach filter, $(PLATFORM_FILTERS), release-$(subst /,-,$(filter))) 18 | RELEASE_TARGETS ?= $(strip $(filter-out $(RELEASE_TARGET_FILTERS), $(foreach arch, $(ARCHES), $(foreach os, $(OSES), release-$(os)-$(arch))))) 19 | DOCKER_PLATFORMS ?= $(subst $(space),$(comma),$(strip $(filter-out $(DOCKER_PLATFORM_FILTERS), $(foreach arch, $(ARCHES), $(foreach os, $(OSES), $(os)/$(arch)))))) 20 | 21 | ifdef CI_VERSION 22 | VERSION := $(CI_VERSION) 23 | endif 24 | 25 | target = $(subst -,$(space),$(@)) 26 | os = $(word 2, $(target)) 27 | arch = $(word 3, $(target)) 28 | 29 | .PHONY: build test release $(RELEASE_TARGETS) docker 30 | 31 | .DEFAULT_GOAL := build 32 | 33 | generate: 34 | go generate 35 | 36 | build: 37 | GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=0 go build \ 38 | -ldflags="-w -s -X main.Version=$(VERSION)" \ 39 | -o bin/ 40 | 41 | test: 42 | CGO_ENABLED=0 go test $(PKGS) 43 | 44 | release: $(RELEASE_TARGETS) 45 | $(RELEASE_TARGETS): 46 | mkdir -p ./release/$(os)-$(arch)/$(VERSION) 47 | GOOS=$(os) GOARCH=$(arch) CGO_ENABLED=0 go build \ 48 | -ldflags="-w -s -X main.Version=$(VERSION)" \ 49 | -o ./release/$(os)-$(arch)/$(VERSION)/ 50 | 51 | docker: 52 | docker buildx build \ 53 | --target $(DOCKER_TARGET) \ 54 | --platform $(DOCKER_PLATFORMS) \ 55 | --build-arg VERSION=$(VERSION) \ 56 | -t $(REGISTRY)/boxboat/$(BINARY):$(VERSION) \ 57 | --push \ 58 | --progress $(PROGRESS) \ 59 | . 60 | 61 | clean: 62 | rm -rf bin release 63 | -------------------------------------------------------------------------------- /pkg/generated/controllers/dhs.dockhand.dev/v1alpha2/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | // Code generated by main. DO NOT EDIT. 17 | 18 | package v1alpha2 19 | 20 | import ( 21 | v1alpha2 "github.com/boxboat/dockhand-secrets-operator/pkg/apis/dhs.dockhand.dev/v1alpha2" 22 | "github.com/rancher/lasso/pkg/controller" 23 | "github.com/rancher/wrangler/v3/pkg/generic" 24 | "github.com/rancher/wrangler/v3/pkg/schemes" 25 | "k8s.io/apimachinery/pkg/runtime/schema" 26 | ) 27 | 28 | func init() { 29 | schemes.Register(v1alpha2.AddToScheme) 30 | } 31 | 32 | type Interface interface { 33 | Profile() ProfileController 34 | Secret() SecretController 35 | } 36 | 37 | func New(controllerFactory controller.SharedControllerFactory) Interface { 38 | return &version{ 39 | controllerFactory: controllerFactory, 40 | } 41 | } 42 | 43 | type version struct { 44 | controllerFactory controller.SharedControllerFactory 45 | } 46 | 47 | func (v *version) Profile() ProfileController { 48 | return generic.NewController[*v1alpha2.Profile, *v1alpha2.ProfileList](schema.GroupVersionKind{Group: "dhs.dockhand.dev", Version: "v1alpha2", Kind: "Profile"}, "profiles", true, v.controllerFactory) 49 | } 50 | 51 | func (v *version) Secret() SecretController { 52 | return generic.NewController[*v1alpha2.Secret, *v1alpha2.SecretList](schema.GroupVersionKind{Group: "dhs.dockhand.dev", Version: "v1alpha2", Kind: "Secret"}, "secrets", true, v.controllerFactory) 53 | } 54 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/templates/controller/rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "dockhand-secrets-operator.name" . }}-controller-sa 6 | labels: 7 | {{- include "dockhand-secrets-operator.labels" . | nindent 4 }} 8 | {{- with .Values.controller.rbac.serviceAccount.annotations }} 9 | annotations: 10 | {{ toYaml . | nindent 4 }} 11 | {{- end }} 12 | --- 13 | apiVersion: rbac.authorization.k8s.io/v1 14 | kind: ClusterRole 15 | metadata: 16 | name: {{ include "dockhand-secrets-operator.name" . }}-controller-sa-cluster-role 17 | labels: 18 | {{- include "dockhand-secrets-operator.labels" . | nindent 4 }} 19 | rules: 20 | - apiGroups: [ "*" ] 21 | resources: 22 | - events 23 | - secrets 24 | - daemonsets 25 | - deployments 26 | - statefulsets 27 | - dockhandsecrets 28 | - dockhandsecrets/status 29 | - dockhandsecretsprofiles 30 | - dockhandsecretsprofiles/status 31 | verbs: 32 | - get 33 | - delete 34 | - create 35 | - patch 36 | - update 37 | - list 38 | - watch 39 | - apiGroups: [ "dhs.dockhand.dev" ] 40 | resources: 41 | - secrets 42 | - secrets/status 43 | - profiles 44 | - profiles/status 45 | verbs: 46 | - get 47 | - delete 48 | - create 49 | - patch 50 | - update 51 | - list 52 | - watch 53 | --- 54 | apiVersion: rbac.authorization.k8s.io/v1 55 | kind: ClusterRoleBinding 56 | metadata: 57 | name: {{ include "dockhand-secrets-operator.name" . }}-controller-sa-role-binding 58 | labels: 59 | {{- include "dockhand-secrets-operator.labels" . | nindent 4 }} 60 | roleRef: 61 | apiGroup: rbac.authorization.k8s.io 62 | kind: ClusterRole 63 | name: {{ include "dockhand-secrets-operator.name" . }}-controller-sa-cluster-role 64 | subjects: 65 | - kind: ServiceAccount 66 | name: {{ include "dockhand-secrets-operator.name" . }}-controller-sa 67 | namespace: {{ .Release.Namespace }} 68 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/templates/webhook/mutating-webhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: MutatingWebhookConfiguration 4 | metadata: 5 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook.dhs.dockhand.dev 6 | labels: 7 | app.kubernetes.io/name: {{ include "dockhand-secrets-operator.name" . }}-webhook.dhs.dockhand.dev 8 | webhooks: 9 | - name: {{ include "dockhand-secrets-operator.name" . }}-webhook-v1.dhs.dockhand.dev 10 | failurePolicy: Fail 11 | objectSelector: 12 | matchLabels: 13 | "dockhand.boxboat.io/autoUpdate": "true" 14 | clientConfig: 15 | service: 16 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook 17 | namespace: {{ .Release.Namespace }} 18 | path: "/mutate" 19 | rules: 20 | - apiGroups: 21 | - "apps" 22 | apiVersions: 23 | - "v1" 24 | operations: 25 | - "CREATE" 26 | - "UPDATE" 27 | resources: 28 | - "daemonsets" 29 | - "deployments" 30 | - "statefulsets" 31 | scope: "*" 32 | admissionReviewVersions: 33 | - "v1" 34 | sideEffects: None 35 | timeoutSeconds: 30 36 | - name: {{ include "dockhand-secrets-operator.name" . }}-webhook.dhs.dockhand.dev 37 | failurePolicy: Fail 38 | objectSelector: 39 | matchLabels: 40 | "dhs.dockhand.dev/autoUpdate": "true" 41 | clientConfig: 42 | service: 43 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook 44 | namespace: {{ .Release.Namespace }} 45 | path: "/mutate" 46 | rules: 47 | - apiGroups: 48 | - "apps" 49 | apiVersions: 50 | - "v1" 51 | operations: 52 | - "CREATE" 53 | - "UPDATE" 54 | resources: 55 | - "daemonsets" 56 | - "deployments" 57 | - "statefulsets" 58 | scope: "*" 59 | admissionReviewVersions: 60 | - "v1" 61 | sideEffects: None 62 | timeoutSeconds: 30 63 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator/templates/webhook/rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook-sa 6 | labels: 7 | {{- include "dockhand-secrets-operator.labels" . | nindent 4 }} 8 | {{- with .Values.webhook.rbac.serviceAccount.annotations }} 9 | annotations: 10 | {{ toYaml . | nindent 4 }} 11 | {{- end }} 12 | --- 13 | apiVersion: rbac.authorization.k8s.io/v1 14 | kind: ClusterRole 15 | metadata: 16 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook-sa-cluster-role 17 | labels: 18 | {{- include "dockhand-secrets-operator.labels" . | nindent 4 }} 19 | rules: 20 | - apiGroups: 21 | - admissionregistration.k8s.io 22 | resources: 23 | - mutatingwebhookconfigurations 24 | verbs: 25 | - get 26 | - create 27 | - patch 28 | - update 29 | - list 30 | - apiGroups: 31 | - coordination.k8s.io 32 | resources: 33 | - leases 34 | verbs: 35 | - '*' 36 | - apiGroups: 37 | - apps 38 | resources: 39 | - deployments 40 | resourceNames: 41 | - {{ include "dockhand-secrets-operator.name" . }}-webhook 42 | verbs: 43 | - get 44 | - patch 45 | - update 46 | - apiGroups: [ "" ] 47 | resources: 48 | - secrets 49 | verbs: 50 | - get 51 | - create 52 | - patch 53 | - update 54 | - list 55 | - apiGroups: [ "" ] 56 | resources: 57 | - configmaps 58 | verbs: 59 | - get 60 | --- 61 | apiVersion: rbac.authorization.k8s.io/v1 62 | kind: ClusterRoleBinding 63 | metadata: 64 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook-sa-role-binding 65 | labels: 66 | {{- include "dockhand-secrets-operator.labels" . | nindent 4 }} 67 | roleRef: 68 | apiGroup: rbac.authorization.k8s.io 69 | kind: ClusterRole 70 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook-sa-cluster-role 71 | subjects: 72 | - kind: ServiceAccount 73 | name: {{ include "dockhand-secrets-operator.name" . }}-webhook-sa 74 | namespace: {{ .Release.Namespace }} 75 | -------------------------------------------------------------------------------- /pkg/apis/dhs.dockhand.dev/v1alpha2/zz_generated_register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | // Code generated by main. DO NOT EDIT. 17 | 18 | // +k8s:deepcopy-gen=package 19 | // +groupName=dhs.dockhand.dev 20 | package v1alpha2 21 | 22 | import ( 23 | dhs "github.com/boxboat/dockhand-secrets-operator/pkg/apis/dhs.dockhand.dev" 24 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 | "k8s.io/apimachinery/pkg/runtime" 26 | "k8s.io/apimachinery/pkg/runtime/schema" 27 | ) 28 | 29 | var ( 30 | ProfileResourceName = "profiles" 31 | SecretResourceName = "secrets" 32 | ) 33 | 34 | // SchemeGroupVersion is group version used to register these objects 35 | var SchemeGroupVersion = schema.GroupVersion{Group: dhs.GroupName, Version: "v1alpha2"} 36 | 37 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind 38 | func Kind(kind string) schema.GroupKind { 39 | return SchemeGroupVersion.WithKind(kind).GroupKind() 40 | } 41 | 42 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 43 | func Resource(resource string) schema.GroupResource { 44 | return SchemeGroupVersion.WithResource(resource).GroupResource() 45 | } 46 | 47 | var ( 48 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 49 | AddToScheme = SchemeBuilder.AddToScheme 50 | ) 51 | 52 | // Adds the list of known types to Scheme. 53 | func addKnownTypes(scheme *runtime.Scheme) error { 54 | scheme.AddKnownTypes(SchemeGroupVersion, 55 | &Profile{}, 56 | &ProfileList{}, 57 | &Secret{}, 58 | &SecretList{}, 59 | ) 60 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /pkg/generated/controllers/dhs.dockhand.dev/factory.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | // Code generated by main. DO NOT EDIT. 17 | 18 | package dhs 19 | 20 | import ( 21 | "github.com/rancher/lasso/pkg/controller" 22 | "github.com/rancher/wrangler/v3/pkg/generic" 23 | "k8s.io/client-go/rest" 24 | ) 25 | 26 | type Factory struct { 27 | *generic.Factory 28 | } 29 | 30 | func NewFactoryFromConfigOrDie(config *rest.Config) *Factory { 31 | f, err := NewFactoryFromConfig(config) 32 | if err != nil { 33 | panic(err) 34 | } 35 | return f 36 | } 37 | 38 | func NewFactoryFromConfig(config *rest.Config) (*Factory, error) { 39 | return NewFactoryFromConfigWithOptions(config, nil) 40 | } 41 | 42 | func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) { 43 | return NewFactoryFromConfigWithOptions(config, &FactoryOptions{ 44 | Namespace: namespace, 45 | }) 46 | } 47 | 48 | type FactoryOptions = generic.FactoryOptions 49 | 50 | func NewFactoryFromConfigWithOptions(config *rest.Config, opts *FactoryOptions) (*Factory, error) { 51 | f, err := generic.NewFactoryFromConfigWithOptions(config, opts) 52 | return &Factory{ 53 | Factory: f, 54 | }, err 55 | } 56 | 57 | func NewFactoryFromConfigWithOptionsOrDie(config *rest.Config, opts *FactoryOptions) *Factory { 58 | f, err := NewFactoryFromConfigWithOptions(config, opts) 59 | if err != nil { 60 | panic(err) 61 | } 62 | return f 63 | } 64 | 65 | func (c *Factory) Dhs() Interface { 66 | return New(c.ControllerFactory()) 67 | } 68 | 69 | func (c *Factory) WithAgent(userAgent string) Interface { 70 | return New(controller.NewSharedControllerFactoryWithAgent(userAgent, c.ControllerFactory())) 71 | } 72 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/menu-filetree.html: -------------------------------------------------------------------------------- 1 | {{ $current := . }} 2 | {{ template "tree-nav" dict "sect" .Site.Home.Sections "current" $current }} 3 | 4 | 5 | {{ define "tree-nav" }} 6 | {{ $current := .current }} 7 | 8 | 48 | {{ end }} 49 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/favicon/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/content/usage/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting Started 3 | weight: -80 4 | --- 5 | 6 | This page tells you how to get started with the dockhand-secrets-operator, including installation and basic usage. 7 | 8 | 9 | 10 | {{< toc >}} 11 | 12 | ## Install 13 | 14 | `dockhand-secrets-operator` is installed via 2 Helm charts: 15 | - dockhand-secrets-operator-crd 16 | - dockhand-secrets-operator 17 | 18 | These charts can be found in the [charts](https://github.com/boxboat/dockhand-secrets-operator/charts) directory. 19 | 20 | ```Shell 21 | # install dockhand-secrets-operator-crd 22 | helm repo add dso https://boxboat.github.io/dockhand-secrets-operator/charts 23 | helm repo update 24 | helm install --namespace dockhand-secrets-operator dso/dockhand-secrets-operator-crd 25 | 26 | # install dockhand-secrets-operator 27 | helm repo add dso https://boxboat.github.io/dockhand-secrets-operator/charts 28 | helm repo update 29 | helm install --namespace dockhand-secrets-operator dso/dockhand-secrets-operator 30 | ``` 31 | 32 | ## Add Dockhand Profile 33 | Once the operator is installed, you will need to give it access to the Secrets Manager(s) that you want to use on the cluster. This is accomplished by creating a `Profile`. See [core-concepts](/usage/core-concepts) 34 | 35 | ## Add Dockhand Secrets 36 | Start adding Dockhand `Secrets` to your deployment manifests! See [core-concepts](/usage/core-concepts) 37 | 38 | ## Deprecations 39 | See [crd-specs](/usage/crd-specs) for current full specifications 40 | 41 | Note removed in `1.0.0` 42 | 43 | ### Deprecation `version: v1alpha1 DockhandProfile` 44 | Changes: 45 | * `version: dockhand.boxboat.io/v1alpha1` -> `version: dhs.dockhand.dev/v1alpha2` 46 | * `kind: DockhandProfile` -> `kind: Profile` 47 | 48 | ### Deprecation `version: v1alpha1 DockhandSecret` 49 | Changes: 50 | * `version: dockhand.boxboat.io/v1alpha1` -> `version: dhs.dockhand.dev/v1alpha2` 51 | * `kind: DockhandSecret` -> `kind: Secret` 52 | * `profile: ` -> `profile.name: ` `profile.namespace: ` 53 | * `profile` field is now an object that contains a `name` and `namespace` field. 54 | * `v1alpha1` assumed `DockhandProfiles` existed in `dockhand-secrets-operator` namespace and did not support multi-tenant use case. `v1alpha2` allows the operator to operate in a multi-tenant mode or a single tenant mode where `Profiles` can be referenced in any namespace where the `dockhand-secrets-operator` has read access. 55 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/page-footer.html: -------------------------------------------------------------------------------- 1 | {{ $current := . }} 2 | {{ $site := .Site }} 3 | {{ $current.Scratch.Set "prev" false }} 4 | {{ $current.Scratch.Set "getNext" false }} 5 | 6 | {{ $current.Scratch.Set "nextPage" false }} 7 | {{ $current.Scratch.Set "prevPage" false }} 8 | 9 | {{ template "menu_nextprev" dict "sect" $.Site.Data.menu.main.main "current" $current "site" $site }} 10 | 11 | {{ define "menu_nextprev" }} 12 | {{ $current := .current }} 13 | {{ $site := .site }} 14 | 15 | {{ range sort (default (seq 0) .sect) "weight" }} 16 | {{ $current.Scratch.Set "current" $current }} 17 | {{ $current.Scratch.Set "site" $site }} 18 | 19 | {{ $ref := default false .ref }} 20 | {{ if $ref}} 21 | {{ $site := $current.Scratch.Get "site" }} 22 | {{ $this := $site.GetPage .ref }} 23 | {{ $current := $current.Scratch.Get "current" }} 24 | 25 | {{ if $current.Scratch.Get "getNext" }} 26 | {{ $current.Scratch.Set "nextPage" (dict "name" .name "this" $this) }} 27 | {{ $current.Scratch.Set "getNext" false }} 28 | {{ end }} 29 | 30 | {{ if eq $current $this }} 31 | {{ $current.Scratch.Set "prevPage" ($current.Scratch.Get "prev") }} 32 | {{ $current.Scratch.Set "getNext" true }} 33 | {{ end }} 34 | 35 | {{ $current.Scratch.Set "prev" (dict "name" .name "this" $this) }} 36 | {{ end }} 37 | 38 | {{ $sub := default false .sub }} 39 | {{ if $sub }} 40 | {{ template "menu_nextprev" dict "sect" $sub "current" ($current.Scratch.Get "current") "site" ($current.Scratch.Get "site") }} 41 | {{ end }} 42 | {{ end }} 43 | {{ end }} 44 | 45 | 46 | 61 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/menu-bundle.html: -------------------------------------------------------------------------------- 1 | {{ $current := .current }} 2 | {{ template "menu-file" dict "sect" .source "current" $current "site" $current.Site }} 3 | 4 | 5 | {{ define "menu-file" }} 6 | {{ $current := .current }} 7 | {{ $site := .site }} 8 | 9 |
    10 | {{ range sort (default (seq 0) .sect) "weight" }} 11 | {{ $current.Scratch.Set "current" $current }} 12 | {{ $current.Scratch.Set "site" $site }} 13 | 14 |
  • 15 | {{ $ref := default false .ref }} 16 | {{ if $ref}} 17 | {{ $site := $current.Scratch.Get "site" }} 18 | {{ $this := $site.GetPage .ref }} 19 | {{ $current := $current.Scratch.Get "current" }} 20 | {{ $icon := default false .icon }} 21 | {{ $numberOfPages := (add (len $this.Pages) (len $this.Sections)) }} 22 | {{ $isCurrent := eq $current $this }} 23 | {{ $isAncestor := $this.IsAncestor $current }} 24 | {{ $id := substr (sha1 $this.Permalink) 0 8 }} 25 | {{ $doCollapse := and (isset . "sub") (or $this.Params.GeekdocCollapseSection (default false .Site.Params.GeekdocCollapseAllSections)) }} 26 | 27 | {{ if $doCollapse }} 28 | 29 | 42 | {{ end }} 43 | {{ else }} 44 | {{ .name }} 45 | {{ end }} 46 | 47 | {{ with .sub }} 48 | {{ template "menu-file" dict "sect" . "current" ($current.Scratch.Get "current") "site" ($current.Scratch.Get "site") }} 49 | {{ end }} 50 |
  • 51 | 52 | {{ end }} 53 |
54 | {{ end }} 55 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/page-header.html: -------------------------------------------------------------------------------- 1 | {{ $geekdocRepo := default (default false .Site.Params.GeekdocRepo) .Page.Params.GeekdocRepo }} 2 | {{ $geekdocEditPath := default (default false .Site.Params.GeekdocEditPath) .Page.Params.GeekdocEditPath }} 3 | {{ if .File }} 4 | {{ $.Scratch.Set "geekdocFilePath" (default .File.Path .Page.Params.GeekdocFilePath) }} 5 | {{ else }} 6 | {{ $.Scratch.Set "geekdocFilePath" false }} 7 | {{ end }} 8 | 9 | {{ define "breadcrumb" }} 10 | {{ $parent := .page.Parent }} 11 | {{ if $parent }} 12 | {{ $name := (partial "title" $parent) }} 13 | {{ $position := (sub .position 1) }} 14 | {{ $value := (printf "
  • %s
  • /
  • %s" $parent.RelPermalink $parent.RelPermalink $name $position .value) }} 15 | {{ template "breadcrumb" dict "page" $parent "value" $value "position" $position }} 16 | {{ else }} 17 | {{ .value | safeHTML }} 18 | {{ end }} 19 | {{ end }} 20 | 21 | {{ $showBreadcrumb := (and (default true .Page.Params.GeekdocBreadcrumb) (default true .Site.Params.GeekdocBreadcrumb)) }} 22 | {{ $showEdit := (and ($.Scratch.Get "geekdocFilePath") $geekdocRepo $geekdocEditPath) }} 23 | 49 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/layouts/partials/site-header.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | {{ if .MenuEnabled }} 4 | 14 | {{ end }} 15 | 16 | 17 | 18 | {{ .Root.Site.Title }} 19 | 20 | 21 |
    22 | {{ if .Root.Site.Data.menu.extra.header }} 23 | 24 | {{ partial "menu-extra" (dict "current" .Root "source" .Root.Site.Data.menu.extra.header "target" "header") }} 25 | {{ end }} 26 | 27 | 28 | Toggle Dark/Light/Auto mode 29 | 30 | 31 | 32 | Toggle Dark/Light/Auto mode 33 | 34 | 35 | 36 | Toggle Dark/Light/Auto mode 37 | 38 | 39 | 40 | {{ if .Root.Site.Data.menu.extra.header }} 41 | 47 | 48 | 54 | {{ end }} 55 |
    56 |
    57 |
    58 | -------------------------------------------------------------------------------- /.github/workflows/docker.yaml: -------------------------------------------------------------------------------- 1 | name: docker 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**' 7 | - '!charts/**' 8 | branches: 9 | - master 10 | tags: 11 | - '*' 12 | 13 | jobs: 14 | docker: 15 | runs-on: ubuntu-latest 16 | permissions: 17 | id-token: write 18 | packages: write 19 | contents: write 20 | attestations: write 21 | 22 | steps: 23 | - uses: actions/checkout@v5 24 | 25 | - name: Compute Version 26 | id: version 27 | run: | 28 | echo ${GITHUB_REF} 29 | tag=${GITHUB_REF#refs/tags/} 30 | publish="no" 31 | if [ "${tag}" != "${GITHUB_REF}" ]; then 32 | tag=$(echo "${tag}" | sed -e 's/[^a-zA-Z0-9\-\.]/-/g') 33 | version=${tag} 34 | publish="yes" 35 | fi 36 | 37 | branch=${GITHUB_REF#refs/heads/} 38 | if [[ -z "${version}" && "${branch}" != "${GITHUB_REF}" ]]; then 39 | branch=$(echo "${branch}" | sed -e 's/[^a-zA-Z0-9\-\.]/-/g') 40 | version=${branch} 41 | if [[ ${branch} = "master" ]]; then 42 | publish="yes" 43 | fi 44 | fi 45 | 46 | pr=${GITHUB_REF#refs/pull/} 47 | if [[ -z "${version}" && "${pr}" != "${GITHUB_REF}" ]]; then 48 | pr=$(echo "${pr}" | sed -e 's/[^a-zA-Z0-9\-\.]/-/g') 49 | version=${pr} 50 | fi 51 | 52 | if [ -z "${version}" ]; then 53 | echo "Version could not be determined" >&2 54 | exit 1 55 | else 56 | echo CI_VERSION=${version} >> $GITHUB_ENV 57 | echo PUBLISH=${publish} >> $GITHUB_ENV 58 | fi 59 | 60 | - name: Set up QEMU 61 | if: ${{ env.PUBLISH == 'yes' }} 62 | uses: docker/setup-qemu-action@v3 63 | 64 | - name: Set up Buildx 65 | if: ${{ env.PUBLISH == 'yes' }} 66 | uses: docker/setup-buildx-action@v3 67 | with: 68 | buildkitd-flags: --debug 69 | 70 | - name: Login to GitHub Container Registry 71 | if: ${{ env.PUBLISH == 'yes' }} 72 | uses: docker/login-action@v3 73 | with: 74 | registry: ghcr.io 75 | username: ${{ github.repository_owner }} 76 | password: ${{ secrets.GITHUB_TOKEN }} 77 | 78 | - name: Build and push 79 | if: ${{ env.PUBLISH == 'yes' }} 80 | id: push 81 | uses: docker/build-push-action@v6 82 | with: 83 | context: . 84 | platforms: linux/amd64,linux/arm64 85 | push: true 86 | build-args: | 87 | VERSION=${{ env.CI_VERSION }} 88 | tags: | 89 | ghcr.io/boxboat/dockhand-secrets-operator:${{ env.CI_VERSION }} 90 | 91 | - name: Attest ghcr image 92 | if: ${{ env.PUBLISH == 'yes' }} 93 | uses: actions/attest-build-provenance@v3 94 | with: 95 | subject-name: ghcr.io/boxboat/dockhand-secrets-operator 96 | subject-digest: ${{ steps.push.outputs.digest }} 97 | push-to-registry: true 98 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/README.md: -------------------------------------------------------------------------------- 1 | # Geekdoc 2 | 3 | [![Build Status](https://img.shields.io/drone/build/thegeeklab/hugo-geekdoc?logo=drone&server=https%3A%2F%2Fdrone.thegeeklab.de)](https://drone.thegeeklab.de/thegeeklab/hugo-geekdoc) 4 | [![Hugo Version](https://img.shields.io/badge/hugo-0.83-blue.svg)](https://gohugo.io) 5 | [![GitHub release](https://img.shields.io/github/v/release/thegeeklab/hugo-geekdoc)](https://github.com/thegeeklab/hugo-geekdoc/releases/latest) 6 | [![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/hugo-geekdoc)](https://github.com/thegeeklab/hugo-geekdoc/graphs/contributors) 7 | [![License: MIT](https://img.shields.io/github/license/thegeeklab/hugo-geekdoc)](https://github.com/thegeeklab/hugo-geekdoc/blob/main/LICENSE) 8 | 9 | Geekdoc is a simple Hugo theme for documentations. It is intentionally designed as a fast and lean theme and may not fit the requirements of complex projects. If a more feature-complete theme is required there are a lot of got alternatives out there. You can find a demo and the full documentation at [https://geekdocs.de](https://geekdocs.de). 10 | 11 | ![Desktop and mobile preview](https://raw.githubusercontent.com/thegeeklab/hugo-geekdoc/main/images/readme.png) 12 | 13 | ## Build and release process 14 | 15 | This theme is subject to a CI driven build and release process common for software development. During the release build, all necessary assets are automatically built by [gulp](https://gulpjs.com/) and bundled in a release tarball. You can download the latest release from the GitHub [release page](https://github.com/thegeeklab/hugo-geekdoc/releases). 16 | 17 | Due to the fact that `gulp` is used as pre-processor the theme cannot be used from the main branch by default. If you want to use the theme from a cloned branch instead of a release tarball you'll need to install `gulp` locally and run the default pipeline once to create all required assets. 18 | 19 | ```Shell 20 | # install required packages from package.json 21 | npm install 22 | 23 | # run gulp pipeline to build required assets 24 | npx gulp default 25 | ``` 26 | 27 | See the [Getting Started Guide](https://geekdocs.de/usage/getting-started/) for details about the different setup options. 28 | 29 | ## Contributors 30 | 31 | Special thanks goes to all [contributors](https://github.com/thegeeklab/hugo-geekdoc/graphs/contributors). If you would like to contribute, 32 | please see the [instructions](https://github.com/thegeeklab/hugo-geekdoc/blob/main/CONTRIBUTING.md). 33 | 34 | Geekdoc is inspired and partially based on the [hugo-book](https://github.com/alex-shpak/hugo-book) theme, thanks [Alex Shpak](https://github.com/alex-shpak/) for your work. 35 | 36 | ## License 37 | 38 | This project is licensed under the MIT License - see the [LICENSE](https://github.com/thegeeklab/hugo-geekdoc/blob/main/LICENSE) file for details. 39 | 40 | The used SVG icons and generated icon fonts are licensed under the license of the respective icon pack: 41 | 42 | - Font Awesome: [CC BY 4.0 License](https://github.com/FortAwesome/Font-Awesome#license) 43 | - IcoMoon Free Pack: [GPL/CC BY 4.0](https://icomoon.io/#icons-icomoon) 44 | - Material Icons: [Apache License 2.0](https://github.com/google/material-design-icons/blob/main/LICENSE) 45 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/static/js/auto-render-e6e57901eb.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={974:function(t){t.exports=e}},r={};function n(e){var a=r[e];if(void 0!==a)return a.exports;var i=r[e]={exports:{}};return t[e](i,i.exports,n),i.exports}n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,{a:t}),t},n.d=function(e,t){for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)};var a={};return function(){n.d(a,{default:function(){return s}});var e=n(974),t=n.n(e),r=function(e,t,r){for(var n=r,a=0,i=e.length;n0&&(a.push({type:"text",data:e.slice(0,n)}),e=e.slice(n));var l=t.findIndex((function(t){return e.startsWith(t.left)}));if(-1===(n=r(t[l].right,e,t[l].left.length)))break;var d=e.slice(0,n+t[l].right.length),s=i.test(d)?d:e.slice(t[l].left.length,n);a.push({type:"math",data:s,rawData:d,display:t[l].display}),e=e.slice(n+t[l].right.length)}return""!==e&&a.push({type:"text",data:e}),a},l=function(e,r){var n=o(e,r.delimiters);if(1===n.length&&"text"===n[0].type)return null;for(var a=document.createDocumentFragment(),i=0;i 2 | 3 | 4 | 22 | 24 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 59 | 72 | 75 | 81 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /cmd/operator.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | dockcmdCommon "github.com/boxboat/dockcmd/cmd/common" 21 | "github.com/boxboat/dockhand-secrets-operator/pkg/common" 22 | controllerv2 "github.com/boxboat/dockhand-secrets-operator/pkg/controller/v2" 23 | dockhandv2 "github.com/boxboat/dockhand-secrets-operator/pkg/generated/controllers/dhs.dockhand.dev" 24 | "github.com/rancher/wrangler/v3/pkg/generated/controllers/apps" 25 | "github.com/rancher/wrangler/v3/pkg/generated/controllers/core" 26 | "github.com/rancher/wrangler/v3/pkg/kubeconfig" 27 | "github.com/rancher/wrangler/v3/pkg/start" 28 | "github.com/sirupsen/logrus" 29 | "github.com/spf13/cobra" 30 | "github.com/spf13/viper" 31 | "k8s.io/client-go/kubernetes" 32 | ) 33 | 34 | type OperatorArgs struct { 35 | MasterURL string 36 | KubeconfigFile string 37 | Namespace string 38 | CrossNamespaceProfileAccessAuthorized bool 39 | } 40 | 41 | var ( 42 | operatorArgs OperatorArgs 43 | ) 44 | 45 | // awsRegionCmdPersistentPreRunE checks required persistent tokens 46 | func startOperatorCmdPersistentPreRunE(cmd *cobra.Command, args []string) error { 47 | if err := rootCmdPersistentPreRunE(cmd, args); err != nil { 48 | return err 49 | } 50 | common.Log.Debugln("awsCmdPersistentPreRunE") 51 | return nil 52 | } 53 | 54 | var startOperatorCmd = &cobra.Command{ 55 | Use: "controller", 56 | Short: "controller start", 57 | Long: `start the operator controller with the provided settings`, 58 | PersistentPreRunE: startOperatorCmdPersistentPreRunE, 59 | Run: func(cmd *cobra.Command, args []string) { 60 | 61 | dockcmdCommon.UseAlternateDelims = true 62 | 63 | // load the kubeconfig file 64 | cfg, err := kubeconfig.GetNonInteractiveClientConfig( 65 | operatorArgs.KubeconfigFile).ClientConfig() 66 | if err != nil { 67 | logrus.Fatalf("Error building kubeconfig: %s", err.Error()) 68 | } 69 | 70 | // Generated controllers 71 | apps := apps.NewFactoryFromConfigOrDie(cfg) 72 | core := core.NewFactoryFromConfigOrDie(cfg) 73 | dhv2 := dockhandv2.NewFactoryFromConfigOrDie(cfg) 74 | kubeClient := kubernetes.NewForConfigOrDie(cfg) 75 | 76 | controllerv2.Register( 77 | cmd.Context(), 78 | operatorArgs.Namespace, 79 | kubeClient.CoreV1().Events(""), 80 | apps.Apps().V1().DaemonSet(), 81 | apps.Apps().V1().Deployment(), 82 | apps.Apps().V1().StatefulSet(), 83 | core.Core().V1().Secret(), 84 | dhv2.Dhs().V1alpha2().Secret(), 85 | dhv2.Dhs().V1alpha2().Profile(), 86 | operatorArgs.CrossNamespaceProfileAccessAuthorized) 87 | 88 | // Start all the controllers 89 | if err := start.All(cmd.Context(), 2, apps, core, dhv2); err != nil { 90 | logrus.Fatalf("Error starting: %s", err.Error()) 91 | } 92 | <-cmd.Context().Done() 93 | }, 94 | } 95 | 96 | // setup command 97 | func init() { 98 | rootCmd.AddCommand(startOperatorCmd) 99 | 100 | startOperatorCmd.PersistentFlags().StringVar( 101 | &operatorArgs.KubeconfigFile, 102 | "kubeconfig", 103 | "", 104 | "Path to a kubeconfig. Only required if out of cluster") 105 | 106 | startOperatorCmd.PersistentFlags().StringVar( 107 | &operatorArgs.MasterURL, 108 | "master", 109 | "", 110 | "Address of Kube API server. Overrides value in kubeconfig. Only required if out of cluster.") 111 | 112 | startOperatorCmd.PersistentFlags().StringVar( 113 | &operatorArgs.Namespace, 114 | "namespace", 115 | "", 116 | "Namespace where the operator is deployed.") 117 | 118 | startOperatorCmd.PersistentFlags().BoolVar( 119 | &operatorArgs.CrossNamespaceProfileAccessAuthorized, 120 | "allow-cross-namespace", 121 | false, 122 | "Allow Secrets to specify Profiles in external namespaces. i.e. Secret Alpha in namespace alpha could reference a profile in namespace Bravo") 123 | 124 | _ = viper.BindPFlags(startOperatorCmd.PersistentFlags()) 125 | } 126 | -------------------------------------------------------------------------------- /pkg/common/tls.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/tls" 8 | "crypto/x509" 9 | "crypto/x509/pkix" 10 | "encoding/pem" 11 | "fmt" 12 | "math/big" 13 | "time" 14 | ) 15 | 16 | const EncryptionBits = 4096 17 | const CertValidity = time.Hour * 24 * 365 18 | 19 | func ValidDaysRemaining(pem []byte) int { 20 | cert, err := x509.ParseCertificate(pem) 21 | if err != nil { 22 | Log.Warnf("could not parse certificate, %v", err) 23 | return -1 24 | } 25 | return int(cert.NotAfter.Sub(time.Now()).Hours() / 24) 26 | } 27 | 28 | func GenerateSelfSignedCA(commonName string) ([]byte, []byte, error) { 29 | serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 256) 30 | serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 31 | if err != nil { 32 | return nil, nil, fmt.Errorf("failed to generate serial number: %s", err) 33 | } 34 | template := &x509.Certificate{ 35 | SerialNumber: serialNumber, 36 | KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 37 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 38 | NotBefore: time.Now(), 39 | NotAfter: time.Now().Add(CertValidity), 40 | Subject: pkix.Name{CommonName: commonName}, 41 | IsCA: true, 42 | MaxPathLenZero: true, 43 | BasicConstraintsValid: true, 44 | } 45 | 46 | key, err := rsa.GenerateKey(rand.Reader, EncryptionBits) 47 | if err != nil { 48 | return nil, nil, fmt.Errorf("failed to generate key: %s", err) 49 | } 50 | 51 | derBytes, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key) 52 | if err != nil { 53 | return nil, nil, fmt.Errorf("failed to create certificate: %s", err) 54 | } 55 | 56 | var certPem, keyPem bytes.Buffer 57 | if err := pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { 58 | return nil, nil, fmt.Errorf("failed to encode certificate: %s", err) 59 | } 60 | if err := pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil { 61 | return nil, nil, fmt.Errorf("failed to encode key: %s", err) 62 | } 63 | 64 | return certPem.Bytes(), keyPem.Bytes(), nil 65 | } 66 | 67 | func GenerateSignedCert(commonName string, dnsNames []string, caPem []byte, caKey []byte) ([]byte, []byte, error) { 68 | key, err := rsa.GenerateKey(rand.Reader, EncryptionBits) 69 | if err != nil { 70 | return nil, nil, fmt.Errorf("failed to generate key: %s", err) 71 | } 72 | csrDerBytes, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{}, key) 73 | if err != nil { 74 | return nil, nil, fmt.Errorf("failed to generate csr: %s", err.Error()) 75 | } 76 | csr, err := x509.ParseCertificateRequest(csrDerBytes) 77 | if err != nil { 78 | return nil, nil, fmt.Errorf("failed to parse csr: %s", err.Error()) 79 | } 80 | 81 | serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 256) 82 | serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 83 | if err != nil { 84 | return nil, nil, fmt.Errorf("failed to generate serial number: %s", err) 85 | } 86 | template := &x509.Certificate{ 87 | SerialNumber: serialNumber, 88 | KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 89 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 90 | NotBefore: time.Now(), 91 | NotAfter: time.Now().Add(CertValidity), 92 | Subject: pkix.Name{CommonName: commonName}, 93 | DNSNames: dnsNames, 94 | } 95 | caTlsPair, err := tls.X509KeyPair(caPem, caKey) 96 | if err != nil { 97 | return nil, nil, fmt.Errorf("failed to load CA key pair: %s", err) 98 | } 99 | 100 | ca, err := x509.ParseCertificate(caTlsPair.Certificate[0]) 101 | if err != nil { 102 | return nil, nil, fmt.Errorf("failed to parse CA certificate: %s", err) 103 | } 104 | 105 | derBytes, err := x509.CreateCertificate(rand.Reader, template, ca, csr.PublicKey, caTlsPair.PrivateKey) 106 | if err != nil { 107 | return nil, nil, fmt.Errorf("failed to create certificate: %s", err) 108 | } 109 | 110 | var certPem, keyPem bytes.Buffer 111 | if err := pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { 112 | return nil, nil, fmt.Errorf("failed to encode certificate: %s", err) 113 | } 114 | if err := pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil { 115 | return nil, nil, fmt.Errorf("failed to encode key: %s", err) 116 | } 117 | 118 | return certPem.Bytes(), keyPem.Bytes(), nil 119 | } 120 | -------------------------------------------------------------------------------- /pkg/apis/dhs.dockhand.dev/v1alpha2/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha2 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | const ( 24 | AutoUpdateLabelKey = "dhs.dockhand.dev/autoUpdate" 25 | DockhandSecretLabelKey = "dhs.dockhand.dev/ownedByDockhandSecret" 26 | DockhandSecretNamesLabelPrefixKey = "secret.dhs.dockhand.dev/" 27 | SecretNamesAnnotationKey = "dhs.dockhand.dev/secretNames" 28 | SecretChecksumAnnotationKey = "dhs.dockhand.dev/secretChecksum" 29 | Ready SecretState = "Ready" 30 | Pending SecretState = "Pending" 31 | ErrApplied SecretState = "ErrApplied" 32 | ) 33 | 34 | type SecretState string 35 | 36 | // SecretRef specifies a reference to a Secret 37 | type SecretRef struct { 38 | Name string `json:"name"` 39 | Key string `json:"key"` 40 | } 41 | 42 | // AwsSecretsManager specifies the configuration for accessing AWS Secrets. 43 | type AwsSecretsManager struct { 44 | CacheTTL string `json:"cacheTTL"` 45 | Region string `json:"region"` 46 | AccessKeyId *string `json:"accessKeyId,omitempty"` 47 | SecretAccessKeyRef *SecretRef `json:"secretAccessKeyRef,omitempty"` 48 | } 49 | 50 | // AzureKeyVault specifies the configuration for accessing Azure Key Vault secrets. 51 | type AzureKeyVault struct { 52 | CacheTTL string `json:"cacheTTL"` 53 | Tenant string `json:"tenant"` 54 | ClientId *string `json:"clientId,omitempty"` 55 | ClientSecretRef *SecretRef `json:"clientSecretRef,omitempty"` 56 | KeyVault string `json:"keyVault"` 57 | } 58 | 59 | type GcpSecretsManager struct { 60 | CacheTTL string `json:"cacheTTL"` 61 | Project string `json:"project"` 62 | CredentialsFileSecretRef *SecretRef `json:"credentialsFileSecretRef"` 63 | } 64 | 65 | // Vault specifies the configuration for accessing Vault secrets. 66 | type Vault struct { 67 | CacheTTL string `json:"cacheTTL"` 68 | Addr string `json:"addr"` 69 | RoleId *string `json:"roleId,omitempty"` 70 | SecretIdRef *SecretRef `json:"secretIdRef,omitempty"` 71 | TokenRef *SecretRef `json:"tokenRef,omitempty"` 72 | } 73 | 74 | // +genclient 75 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 76 | 77 | // Profile is a specification for a DockhandProfile resource 78 | type Profile struct { 79 | metav1.TypeMeta `json:",inline"` 80 | metav1.ObjectMeta `json:"metadata,omitempty"` 81 | 82 | AwsSecretsManager *AwsSecretsManager `json:"awsSecretsManager,omitempty"` 83 | AzureKeyVault *AzureKeyVault `json:"azureKeyVault,omitempty"` 84 | GcpSecretsManager *GcpSecretsManager `json:"gcpSecretsManager,omitempty"` 85 | Vault *Vault `json:"vault,omitempty"` 86 | } 87 | 88 | // +genclient 89 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 90 | 91 | // Secret is a specification for a Secret resource. 92 | type Secret struct { 93 | metav1.TypeMeta `json:",inline"` 94 | metav1.ObjectMeta `json:"metadata,omitempty"` 95 | 96 | SyncInterval string `json:"syncInterval"` 97 | Data map[string]string `json:"data"` 98 | SecretSpec SecretSpec `json:"secretSpec"` 99 | Profile ProfileRef `json:"profile"` 100 | Status SecretStatus `json:"status,omitempty"` 101 | } 102 | 103 | type ProfileRef struct { 104 | Name string `json:"name"` 105 | Namespace string `json:"namespace"` 106 | } 107 | 108 | // SecretSpec defines the kubernetes secret data to use for the secret managed by a Secret 109 | type SecretSpec struct { 110 | Name string `json:"name"` 111 | Type string `json:"type"` 112 | Labels map[string]string `json:"labels"` 113 | Annotations map[string]string `json:"annotations"` 114 | } 115 | 116 | type SecretStatus struct { 117 | State SecretState `json:"state"` 118 | ObservedAnnotationChecksum string `json:"observedAnnotationChecksum"` 119 | ObservedGeneration int64 `json:"observedGeneration"` 120 | ObservedSecretResourceVersion string `json:"observedSecretResourceVersion"` 121 | SyncTimestamp string `json:"syncTimestamp"` 122 | } 123 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdocs/assets/js/search.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | {{ $searchDataFile := printf "%s.search-data.json" .Language.Lang }} 4 | {{ $searchData := resources.Get "search-data.json" | resources.ExecuteAsTemplate $searchDataFile . | resources.Minify }} 5 | 6 | (function() { 7 | const input = document.querySelector('#gdoc-search-input'); 8 | const results = document.querySelector('#gdoc-search-results'); 9 | let showParent = {{ if .Site.Params.GeekdocSearchShowParent }}true{{ else }}false{{ end }} 10 | 11 | if (input) { 12 | input.addEventListener('focus', init); 13 | input.addEventListener('keyup', search); 14 | } 15 | 16 | function init() { 17 | input.removeEventListener('focus', init); // init once 18 | 19 | loadScript('{{ index .Site.Data.assets "js/groupBy.min.js" | relURL }}'); 20 | loadScript('{{ index .Site.Data.assets "js/flexsearch.min.js" | relURL }}', function() { 21 | const indexCfgDefaults = { 22 | tokenize: 'forward' 23 | } 24 | const indexCfg = {{ with .Scratch.Get "geekdocSearchConfig" }}{{ . | jsonify }}{{ else }}indexCfgDefaults{{ end }}; 25 | const dataUrl = '{{ $searchData.RelPermalink }}' 26 | 27 | indexCfg.document = { 28 | key: 'id', 29 | index: ['title', 'content'], 30 | store: ['title', 'href', 'parent'], 31 | }; 32 | 33 | const index = new FlexSearch.Document(indexCfg); 34 | window.geekdocSearchIndex = index; 35 | 36 | getJson(dataUrl, function(data) { 37 | data.forEach(obj => { 38 | window.geekdocSearchIndex.add(obj); 39 | }); 40 | }); 41 | }); 42 | } 43 | 44 | function search() { 45 | const searchCfg = { 46 | enrich: true, 47 | limit: 10 48 | }; 49 | 50 | while (results.firstChild) { 51 | results.removeChild(results.firstChild); 52 | } 53 | 54 | if (!input.value) { 55 | return results.classList.remove('has-hits'); 56 | } 57 | 58 | let searchHits = flattenHits(window.geekdocSearchIndex.search(input.value, searchCfg)); 59 | if (searchHits.length < 1) { 60 | return results.classList.remove('has-hits'); 61 | } 62 | 63 | results.classList.add('has-hits'); 64 | 65 | if (showParent === true) { 66 | searchHits = groupBy(searchHits, hit => hit.parent); 67 | } 68 | 69 | const items = []; 70 | 71 | if (showParent === true) { 72 | for (const section in searchHits) { 73 | const item = document.createElement('li'), 74 | title = item.appendChild(document.createElement('span')), 75 | subList = item.appendChild(document.createElement('ul')); 76 | 77 | title.textContent = section; 78 | createLinks(searchHits[section], subList); 79 | 80 | items.push(item); 81 | } 82 | } else { 83 | const item = document.createElement('li'), 84 | title = item.appendChild(document.createElement('span')), 85 | subList = item.appendChild(document.createElement('ul')); 86 | 87 | title.textContent = 'Results'; 88 | createLinks(searchHits, subList); 89 | 90 | items.push(item); 91 | } 92 | 93 | items.forEach(item => { 94 | results.appendChild(item); 95 | }) 96 | } 97 | 98 | /** 99 | * Creates links to given fields and either returns them in an array or attaches them to a target element 100 | * @param {Object} fields Page to which the link should point to 101 | * @param {HTMLElement} target Element to which the links should be attatched 102 | * @returns {Array} If target is not specified, returns an array of built links 103 | */ 104 | function createLinks(pages, target) { 105 | const items = []; 106 | 107 | for (const page of pages) { 108 | const item = document.createElement("li"), 109 | entry = item.appendChild(document.createElement("span")), 110 | a = entry.appendChild(document.createElement("a")); 111 | 112 | entry.classList.add('flex') 113 | 114 | a.href = page.href; 115 | a.textContent = page.title; 116 | a.classList.add('gdoc-search__entry') 117 | 118 | if (target) { 119 | target.appendChild(item); 120 | continue 121 | } 122 | 123 | items.push(item); 124 | } 125 | 126 | return items; 127 | } 128 | 129 | function fetchErrors(response) { 130 | if (!response.ok) { 131 | throw Error(response.statusText); 132 | } 133 | return response; 134 | } 135 | 136 | function getJson(src, callback) { 137 | fetch(src) 138 | .then(fetchErrors) 139 | .then(response => response.json()) 140 | .then(json => callback(json)) 141 | .catch(function(error) { 142 | console.log(error); 143 | }); 144 | } 145 | 146 | function flattenHits(results) { 147 | const items = []; 148 | const map = new Map(); 149 | 150 | for (const field of results) { 151 | for (const page of field.result) { 152 | if(!map.has(page.doc.href)){ 153 | map.set(page.doc.href, true); 154 | items.push(page.doc); 155 | } 156 | } 157 | } 158 | 159 | return items 160 | } 161 | 162 | function loadScript(src, callback) { 163 | let script = document.createElement('script'); 164 | script.defer = true; 165 | script.async = false; 166 | script.src = src; 167 | script.onload = callback; 168 | 169 | document.body.appendChild(script); 170 | } 171 | })(); 172 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator-crd/templates/crd/secret-crd.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: secrets.dhs.dockhand.dev 6 | labels: 7 | app.kubernetes.io/name: secrets.dhs.dockhand.dev 8 | spec: 9 | group: dhs.dockhand.dev 10 | scope: Namespaced 11 | names: 12 | plural: secrets 13 | singular: secret 14 | kind: Secret 15 | shortNames: 16 | - dhs 17 | versions: 18 | - additionalPrinterColumns: 19 | - name: Secret 20 | type: string 21 | jsonPath: .secretSpec.name 22 | - name: Status 23 | type: string 24 | jsonPath: .status.state 25 | - name: Age 26 | type: date 27 | jsonPath: .metadata.creationTimestamp 28 | name: v1alpha2 29 | served: true 30 | storage: true 31 | schema: 32 | openAPIV3Schema: 33 | type: object 34 | properties: 35 | profile: 36 | type: object 37 | description: |- 38 | Profile to use for this secret 39 | properties: 40 | name: 41 | type: string 42 | description: |- 43 | Name of Profile 44 | namespace: 45 | type: string 46 | description: |- 47 | Namespace of profile (optional) defaults to same namespace 48 | syncInterval: 49 | type: string 50 | default: 0s 51 | format: duration 52 | description: |- 53 | Specifies the time interval for polling the secrets backend for changes. 54 | The default value of 0 indicates that no polling will occur and is the 55 | default behavior prior to 1.1.0 release, in this case the operator will only query 56 | the backend when a field in the Dockhand Secret CRD has been modified. 57 | Valid time units are ns, µs (or us), ms, s, m, h, but must exceed 5s (when not 0). 58 | Also note that the operator will not poll the backend more frequently than 59 | the cacheTTL of the profile referenced by the Secret 60 | secretSpec: 61 | type: object 62 | description: |- 63 | Specification to use for creating the Kubernetes Secret 64 | properties: 65 | name: 66 | type: string 67 | description: |- 68 | Name of the secret that will be created or updated with the processed contents of the data field. 69 | type: 70 | type: string 71 | description: |- 72 | Type of k8s secret to create Opaque, kubernetes.io/service-account-token, kubernetes.io/dockercfg, 73 | kubernetes.io/dockerconfigjson, kubernetes.io/basic-auth, kubernetes.io/ssh-auth, kubernetes.io/tls 74 | or bootstrap.kubernetes.io/token 75 | labels: 76 | type: object 77 | nullable: true 78 | description: |- 79 | Optional additional labels to add to the secret managed by this Dockhand Secret 80 | additionalProperties: 81 | type: string 82 | annotations: 83 | type: object 84 | nullable: true 85 | description: |- 86 | Optional additional annotations to add to the secret managed by this Dockhand Secret 87 | additionalProperties: 88 | type: string 89 | status: 90 | type: object 91 | description: |- 92 | Provides basic status for a Dockhand Secret 93 | properties: 94 | state: 95 | type: string 96 | description: |- 97 | Ready, Pending or ErrApplied 98 | observedAnnotationChecksum: 99 | type: string 100 | description: |- 101 | Checksum of observed annotations 102 | observedGeneration: 103 | type: integer 104 | description: |- 105 | The last generation processed by the controller 106 | observedSecretResourceVersion: 107 | type: string 108 | description: |- 109 | The managed secret resource version last observed by the controller 110 | syncTimestamp: 111 | type: string 112 | format: datetime 113 | description: |- 114 | Last time the secret was synced from the backend 115 | data: 116 | type: object 117 | description: |- 118 | Store arbitrary templated secret data here just as you would in a kubernetes configmap. 119 | The dockhand-secrets-operator will retrieve the secrets from the secrets backend and create normal 120 | kubernetes secrets for use by your application. Secrets should be templated using go templating with 121 | alternative delimiters << >> rather than \{\{ \}\}. 122 | additionalProperties: 123 | type: string 124 | subresources: 125 | status: {} 126 | -------------------------------------------------------------------------------- /charts/dockhand-secrets-operator-crd/templates/crd/profile-crd.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: profiles.dhs.dockhand.dev 6 | labels: 7 | app.kubernetes.io/name: profiles.dhs.dockhand.dev 8 | spec: 9 | group: dhs.dockhand.dev 10 | scope: Namespaced 11 | names: 12 | plural: profiles 13 | singular: profile 14 | kind: Profile 15 | shortNames: 16 | - dhp 17 | versions: 18 | - name: v1alpha2 19 | served: true 20 | storage: true 21 | schema: 22 | openAPIV3Schema: 23 | type: object 24 | properties: 25 | awsSecretsManager: 26 | type: object 27 | description: |- 28 | AWS Secrets Manager configuration to allow the Dockhand Secrets Operator 29 | to retrieve Secrets from AWS. If no accessKeyId and secretAccessKey are provided 30 | then chain credentials will be used. 31 | allOf: 32 | - required: 33 | - region 34 | properties: 35 | cacheTTL: 36 | type: string 37 | default: 60s 38 | description: |- 39 | Duration to cache secret responses 40 | region: 41 | type: string 42 | description: |- 43 | AWS Region to retrieve secrets from 44 | accessKeyId: 45 | type: string 46 | description: |- 47 | AWS IAM Access Key 48 | secretAccessKeyRef: 49 | type: object 50 | description: |- 51 | Name of secret containing AWS IAM Secret Access Key in a key named AWS_SECRET_ACCES_KEY 52 | properties: 53 | name: 54 | type: string 55 | description: |- 56 | Name of secret containing AWS IAM Secret Access Key 57 | key: 58 | type: string 59 | description: |- 60 | Key in the secret containing the AWS IAM Secret Access Key 61 | azureKeyVault: 62 | type: object 63 | description: |- 64 | Azure Key Vault configuration to allow the Dockhand Secrets Operator to retrieve Secrets from Azure 65 | allOf: 66 | - required: 67 | - tenant 68 | - keyVault 69 | properties: 70 | cacheTTL: 71 | type: string 72 | default: 60s 73 | format: duration 74 | description: |- 75 | Duration to cache secret responses 76 | tenant: 77 | type: string 78 | description: |- 79 | Azure Tenant ID where the Key Vault resides 80 | clientId: 81 | type: string 82 | description: |- 83 | Azure Client ID to access the Key Vault 84 | clientSecretRef: 85 | type: object 86 | description: |- 87 | Reference to Azure Client Secret 88 | properties: 89 | name: 90 | type: string 91 | description: |- 92 | Name of secret containing Azure Client Secret 93 | key: 94 | type: string 95 | description: |- 96 | Key in the secret containing the Azure Client Secret 97 | keyVault: 98 | type: string 99 | description: |- 100 | Name of Azure Key Vault to retrieve secrets from 101 | gcpSecretsManager: 102 | type: object 103 | description: |- 104 | Google Cloud Platform Secrets Manager Configuration to allow Dockhand Secrets Operator to retrieve secrets 105 | from GCP. Authentication can be Application Default Credentials or by providing a key.json 106 | properties: 107 | cacheTTL: 108 | type: string 109 | default: 60s 110 | description: |- 111 | Duration to cache secret responses 112 | project: 113 | type: string 114 | description: |- 115 | The GCP Project to reference for this profile 116 | credentialsFileSecretRef: 117 | type: object 118 | description: |- 119 | Secret Reference containing JSON credentials file stored in a key named gcp-credentials.json 120 | properties: 121 | name: 122 | type: string 123 | description: |- 124 | Name of secret containing GCP JSON Credentials 125 | key: 126 | type: string 127 | description: |- 128 | Key in the secret containing GCP JSON Credentials 129 | vault: 130 | type: object 131 | description: |- 132 | HashiCorp Vault Configuration to allow Dockhand Secrets Operator to retrieve secrets from Vault. Secrets 133 | can be retrieved with either a roleId/secretId or with a Vault Token. 134 | allOf: 135 | - required: 136 | - addr 137 | properties: 138 | cacheTTL: 139 | type: string 140 | default: 60s 141 | description: |- 142 | Duration to cache secret responses 143 | addr: 144 | type: string 145 | description: |- 146 | Vault Address e.g. http://vault:8200 147 | roleId: 148 | type: string 149 | description: |- 150 | Vault Role ID 151 | secretIdRef: 152 | type: object 153 | description: |- 154 | Reference to secret containing the Vault secretId 155 | properties: 156 | name: 157 | type: string 158 | description: |- 159 | Name of secret containing Vault secretId 160 | key: 161 | type: string 162 | description: |- 163 | Key in the secret containing Vault secretId 164 | tokenRef: 165 | type: object 166 | description: |- 167 | Reference to secret containing the Vault Token 168 | properties: 169 | name: 170 | type: string 171 | description: |- 172 | Name of secret containing Vault Token 173 | key: 174 | type: string 175 | description: |- 176 | Key in the secret containing Vault Token 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dockhand-secrets-operator 2 | ![Main](https://github.com/boxboat/dockhand-secrets-operator/actions/workflows/docker.yaml/badge.svg?branch=master) 3 | ![Helm](https://github.com/boxboat/dockhand-secrets-operator/actions/workflows/helm.yaml/badge.svg?branch=master) 4 | 5 | Secrets management with GitOps can be challenging in Kubernetes environments. Often engineers resort to manual secret creation, injection of secrets through scripts with the CI/CD tool or even worse just committing the secrets directly to git. 6 | 7 | The Dockhand Secrets Operator solves that problem by allowing you to make arbitrary secrets in a familiar way with only the secret bits stored in the backend(s) of your choice - AWS Secrets Manager, Azure Key Vault, GCP Secrets Manager or Vault. Secret references can be stored in git with your Helm chart or Kubernetes manifests. 8 | 9 | The operator supports auto rolling updates for `Deployments`, `StatefulSets` and `DaemonSets` through the use of a single `label` added to the metadata of those items. The operator accomplishes this by injecting an annotation with the checksum of the `Secrets` referenced in those manifests and will update that checksum annotation automatically when the secret changes. 10 | 11 | The operator installation deploys the CRDs, the controller and a mutating webhook to provide auto updates for types mentioned above. 12 | 13 | ## Usage 14 | 1. Install Helm charts from [dockhand-charts](https://github.com/boxboat/dockhand-secrets-operator/tree/master/charts/dockhand-secrets-operator#install-instructions) 15 | 2. Configure Operator with `DockhandSecretsProfile` to connect `dockhand-secrets-operator` to 1 or more Secrets Managers 16 | 3. Create `DockhandSecrets` to manage `Secrets` required by your applications. 17 | 18 | 19 | ### CustomResourceDefinitions 20 | `dockhand-secrets-operator` makes use of 2 CRDs to manage `Secrets`. One provides the data required for the operator to connect to the secrets manager(s) and the other manages `Secrets` 21 | 22 | #### Dockhand Profile 23 | 24 | Example of how to create a `Profile`. 25 | 26 | Note that `dockhand-secrets-operator` has to 2 main operating modes. One that will allow cross namespace access to Dockhand `Profiles` and the default mode which blocks cross namespace access. The default mode supports multi-tenant usage by requiring a `Profile` in each namespace. If you are running a single-tenant cluster then the flag `--allow-cross-namespace` will allow you to specify a `Profile` in another namespace for the operator to utilize. 27 | 28 | The `cacheTTL` field allows you to control how long a Secrets Manager response is cached by the operator. The default is 60 seconds which prevents the `dockhand-secrets-operator` from abusing the Secrets Backend. 29 | 30 | ```yaml 31 | --- 32 | apiVersion: dhs.dockhand.dev/v1alpha2 33 | kind: Profile 34 | metadata: 35 | name: test-dockhand-profile 36 | namespace: dockhand-secrets-operator 37 | awsSecretsManager: 38 | cacheTTL: 60s 39 | region: us-east-1 40 | accessKeyId: 41 | secretAccessKeyRef: 42 | name: dockhand-profile-secrets 43 | key: aws-secret-access-key 44 | azureKeyVault: 45 | cacheTTL: 60s 46 | keyVault: dockcmd 47 | tenant: 48 | clientId: 49 | clientSecretRef: 50 | name: dockhand-profile-secrets 51 | key: azure-client-secret 52 | gcpSecretsManager: 53 | cacheTTL: 60s 54 | project: myproject 55 | credentialsFileSecretRef: 56 | name: dockhand-profile-secrets 57 | key: gcp-credentials.json 58 | vault: 59 | cacheTTL: 60s 60 | addr: http://vault:8200 61 | tokenRef: 62 | name: dockhand-profile-secrets 63 | key: vault-token 64 | --- 65 | apiVersion: v1 66 | kind: Secret 67 | type: Opaque 68 | metadata: 69 | name: dockhand-profile-secrets 70 | namespace: dockhand-secrets-operator 71 | data: 72 | aws-secret-access-key: 73 | vault-token: 74 | azure-client-secret: 75 | gcp-credentials.json: 76 | ``` 77 | 78 | #### Dockhand Secret 79 | The Dockhand `Secret` is essentially a go template with alternate delimiters `<< >>` so that you can use it in a Helm chart. The operator is built off [dockcmd](https://github.com/boxboat/dockcmd). Sprig functions are supported and specific versions of secrets are supported through the use of `?version=` on the secret name. For simplicity `?version=latest` will work with all the backends but specific versions require the value expected by the backend. 80 | 81 | Note that GCP and Azure have 2 forms of supported secrets `text` or `json`. The text version will return the entire secret stored in the key/value where as the json version will interpret the stored value as `json` and allow you retrieve a single `key` in the secret. 82 | 83 | The Dockhand `Secret` will generate a secret of type `secretSpec.type` in the same namespace specified by `secretSpec.name`. Changes to a Dockhand `Secret` will trigger a refresh of the `Secret` managed by that Dockhand `Secret`. You can optionally have labels or annotations injected on the `Secret` created by the Dockhand `Secret`. 84 | 85 | The `profile` field allows you to specify the Dockhand `SecretProfile`, which gives you flexibility to connect to numerous Secrets Managers from the same cluster. 86 | 87 | ```yaml 88 | --- 89 | apiVersion: dhs.dockhand.dev/v1alpha2 90 | kind: Secret 91 | metadata: 92 | name: dockhand-example-secret 93 | profile: 94 | name: dockhand-profile 95 | namespace: dockhand-secrets-operator 96 | secretSpec: 97 | name: example-secret 98 | type: Opaque 99 | # optional 100 | labels: 101 | foo: bar 102 | # optional 103 | annotations: 104 | alpha: charlie 105 | data: 106 | # aws secrets can also be accessed by arn 107 | aws-alpha: << (aws "dockcmd-test" "alpha") >> 108 | aws-bravo: << (aws "dockcmd-test" "bravo") >> 109 | aws-charile: << (aws "dockcmd-test" "charlie") >> 110 | azure-alpha-text: << (azureText "dockcmd-text-test") | squote >> 111 | azure-alpha: << (azureJson "dockcmd-json-test" "alpha" ) | squote >> 112 | azure-bravo: << (azureJson "dockcmd-json-test" "bravo" ) | squote >> 113 | azure-charlie: << (azureJson "dockcmd-json-test" "charlie" ) | squote >> 114 | gcp-alpha-text: << (gcpText "dockcmd-text") | squote >> 115 | gcp-alpha: << (gcpJson "dockcmd-json?version=latest" "alpha" ) | squote >> 116 | gcp-bravo: << (gcpJson "dockcmd-json" "bravo" ) | squote >> 117 | gcp-charlie: << (gcpJson "dockcmd-json" "charlie" ) | squote >> 118 | vault-alpha: << (vault "secret/dockcmd-test?version=1" "alpha" ) | squote >> 119 | vault-bravo: << (vault "secret/dockcmd-test?version=1" "bravo" ) | squote >> 120 | vault-charlie: << (vault "secret/dockcmd-test?version=1" "charlie" ) | squote >> 121 | ``` 122 | 123 | If you are using Dockhand `Secrets` in a Helm chart, and you simply want to retrieve the latest version of the secret everytime helm is executed, place an annotation on the Dockhand `Secret` that generates a timestamp - this will trigger the operator to handle a Dockhand `Secret` change. 124 | ```yaml 125 | annotations: 126 | updateTimestamp: {{ now | date "20060102150405" | quote }} 127 | ``` 128 | 129 | ### Auto Updates 130 | For `DaemonSets`, `Deployments` and `StatefulSets` you can insert the following label, which make the `dockhand-secrets-operator` auto roll those types when a Dockhand `Secret` updates the `Secret` it owns. 131 | 132 | ```yaml 133 | metadata: 134 | labels: 135 | dhs.dockhand.dev/autoUpdate: "true" 136 | ``` 137 | -------------------------------------------------------------------------------- /pkg/generated/controllers/dhs.dockhand.dev/v1alpha2/secret.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | // Code generated by main. DO NOT EDIT. 17 | 18 | package v1alpha2 19 | 20 | import ( 21 | "context" 22 | "sync" 23 | "time" 24 | 25 | v1alpha2 "github.com/boxboat/dockhand-secrets-operator/pkg/apis/dhs.dockhand.dev/v1alpha2" 26 | "github.com/rancher/wrangler/v3/pkg/apply" 27 | "github.com/rancher/wrangler/v3/pkg/condition" 28 | "github.com/rancher/wrangler/v3/pkg/generic" 29 | "github.com/rancher/wrangler/v3/pkg/kv" 30 | "k8s.io/apimachinery/pkg/api/equality" 31 | "k8s.io/apimachinery/pkg/api/errors" 32 | "k8s.io/apimachinery/pkg/runtime" 33 | "k8s.io/apimachinery/pkg/runtime/schema" 34 | ) 35 | 36 | // SecretController interface for managing Secret resources. 37 | type SecretController interface { 38 | generic.ControllerInterface[*v1alpha2.Secret, *v1alpha2.SecretList] 39 | } 40 | 41 | // SecretClient interface for managing Secret resources in Kubernetes. 42 | type SecretClient interface { 43 | generic.ClientInterface[*v1alpha2.Secret, *v1alpha2.SecretList] 44 | } 45 | 46 | // SecretCache interface for retrieving Secret resources in memory. 47 | type SecretCache interface { 48 | generic.CacheInterface[*v1alpha2.Secret] 49 | } 50 | 51 | // SecretStatusHandler is executed for every added or modified Secret. Should return the new status to be updated 52 | type SecretStatusHandler func(obj *v1alpha2.Secret, status v1alpha2.SecretStatus) (v1alpha2.SecretStatus, error) 53 | 54 | // SecretGeneratingHandler is the top-level handler that is executed for every Secret event. It extends SecretStatusHandler by a returning a slice of child objects to be passed to apply.Apply 55 | type SecretGeneratingHandler func(obj *v1alpha2.Secret, status v1alpha2.SecretStatus) ([]runtime.Object, v1alpha2.SecretStatus, error) 56 | 57 | // RegisterSecretStatusHandler configures a SecretController to execute a SecretStatusHandler for every events observed. 58 | // If a non-empty condition is provided, it will be updated in the status conditions for every handler execution 59 | func RegisterSecretStatusHandler(ctx context.Context, controller SecretController, condition condition.Cond, name string, handler SecretStatusHandler) { 60 | statusHandler := &secretStatusHandler{ 61 | client: controller, 62 | condition: condition, 63 | handler: handler, 64 | } 65 | controller.AddGenericHandler(ctx, name, generic.FromObjectHandlerToHandler(statusHandler.sync)) 66 | } 67 | 68 | // RegisterSecretGeneratingHandler configures a SecretController to execute a SecretGeneratingHandler for every events observed, passing the returned objects to the provided apply.Apply. 69 | // If a non-empty condition is provided, it will be updated in the status conditions for every handler execution 70 | func RegisterSecretGeneratingHandler(ctx context.Context, controller SecretController, apply apply.Apply, 71 | condition condition.Cond, name string, handler SecretGeneratingHandler, opts *generic.GeneratingHandlerOptions) { 72 | statusHandler := &secretGeneratingHandler{ 73 | SecretGeneratingHandler: handler, 74 | apply: apply, 75 | name: name, 76 | gvk: controller.GroupVersionKind(), 77 | } 78 | if opts != nil { 79 | statusHandler.opts = *opts 80 | } 81 | controller.OnChange(ctx, name, statusHandler.Remove) 82 | RegisterSecretStatusHandler(ctx, controller, condition, name, statusHandler.Handle) 83 | } 84 | 85 | type secretStatusHandler struct { 86 | client SecretClient 87 | condition condition.Cond 88 | handler SecretStatusHandler 89 | } 90 | 91 | // sync is executed on every resource addition or modification. Executes the configured handlers and sends the updated status to the Kubernetes API 92 | func (a *secretStatusHandler) sync(key string, obj *v1alpha2.Secret) (*v1alpha2.Secret, error) { 93 | if obj == nil { 94 | return obj, nil 95 | } 96 | 97 | origStatus := obj.Status.DeepCopy() 98 | obj = obj.DeepCopy() 99 | newStatus, err := a.handler(obj, obj.Status) 100 | if err != nil { 101 | // Revert to old status on error 102 | newStatus = *origStatus.DeepCopy() 103 | } 104 | 105 | if a.condition != "" { 106 | if errors.IsConflict(err) { 107 | a.condition.SetError(&newStatus, "", nil) 108 | } else { 109 | a.condition.SetError(&newStatus, "", err) 110 | } 111 | } 112 | if !equality.Semantic.DeepEqual(origStatus, &newStatus) { 113 | if a.condition != "" { 114 | // Since status has changed, update the lastUpdatedTime 115 | a.condition.LastUpdated(&newStatus, time.Now().UTC().Format(time.RFC3339)) 116 | } 117 | 118 | var newErr error 119 | obj.Status = newStatus 120 | newObj, newErr := a.client.UpdateStatus(obj) 121 | if err == nil { 122 | err = newErr 123 | } 124 | if newErr == nil { 125 | obj = newObj 126 | } 127 | } 128 | return obj, err 129 | } 130 | 131 | type secretGeneratingHandler struct { 132 | SecretGeneratingHandler 133 | apply apply.Apply 134 | opts generic.GeneratingHandlerOptions 135 | gvk schema.GroupVersionKind 136 | name string 137 | seen sync.Map 138 | } 139 | 140 | // Remove handles the observed deletion of a resource, cascade deleting every associated resource previously applied 141 | func (a *secretGeneratingHandler) Remove(key string, obj *v1alpha2.Secret) (*v1alpha2.Secret, error) { 142 | if obj != nil { 143 | return obj, nil 144 | } 145 | 146 | obj = &v1alpha2.Secret{} 147 | obj.Namespace, obj.Name = kv.RSplit(key, "/") 148 | obj.SetGroupVersionKind(a.gvk) 149 | 150 | if a.opts.UniqueApplyForResourceVersion { 151 | a.seen.Delete(key) 152 | } 153 | 154 | return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts). 155 | WithOwner(obj). 156 | WithSetID(a.name). 157 | ApplyObjects() 158 | } 159 | 160 | // Handle executes the configured SecretGeneratingHandler and pass the resulting objects to apply.Apply, finally returning the new status of the resource 161 | func (a *secretGeneratingHandler) Handle(obj *v1alpha2.Secret, status v1alpha2.SecretStatus) (v1alpha2.SecretStatus, error) { 162 | if !obj.DeletionTimestamp.IsZero() { 163 | return status, nil 164 | } 165 | 166 | objs, newStatus, err := a.SecretGeneratingHandler(obj, status) 167 | if err != nil { 168 | return newStatus, err 169 | } 170 | if !a.isNewResourceVersion(obj) { 171 | return newStatus, nil 172 | } 173 | 174 | err = generic.ConfigureApplyForObject(a.apply, obj, &a.opts). 175 | WithOwner(obj). 176 | WithSetID(a.name). 177 | ApplyObjects(objs...) 178 | if err != nil { 179 | return newStatus, err 180 | } 181 | a.storeResourceVersion(obj) 182 | return newStatus, nil 183 | } 184 | 185 | // isNewResourceVersion detects if a specific resource version was already successfully processed. 186 | // Only used if UniqueApplyForResourceVersion is set in generic.GeneratingHandlerOptions 187 | func (a *secretGeneratingHandler) isNewResourceVersion(obj *v1alpha2.Secret) bool { 188 | if !a.opts.UniqueApplyForResourceVersion { 189 | return true 190 | } 191 | 192 | // Apply once per resource version 193 | key := obj.Namespace + "/" + obj.Name 194 | previous, ok := a.seen.Load(key) 195 | return !ok || previous != obj.ResourceVersion 196 | } 197 | 198 | // storeResourceVersion keeps track of the latest resource version of an object for which Apply was executed 199 | // Only used if UniqueApplyForResourceVersion is set in generic.GeneratingHandlerOptions 200 | func (a *secretGeneratingHandler) storeResourceVersion(obj *v1alpha2.Secret) { 201 | if !a.opts.UniqueApplyForResourceVersion { 202 | return 203 | } 204 | 205 | key := obj.Namespace + "/" + obj.Name 206 | a.seen.Store(key, obj.ResourceVersion) 207 | } 208 | -------------------------------------------------------------------------------- /cmd/server.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 BoxBoat 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "context" 21 | "crypto/tls" 22 | "fmt" 23 | "net/http" 24 | "os" 25 | "os/signal" 26 | "syscall" 27 | "time" 28 | 29 | dockhand "github.com/boxboat/dockhand-secrets-operator/pkg/apis/dhs.dockhand.dev/v1alpha2" 30 | "github.com/boxboat/dockhand-secrets-operator/pkg/common" 31 | "github.com/boxboat/dockhand-secrets-operator/pkg/k8s" 32 | "github.com/boxboat/dockhand-secrets-operator/pkg/webhook" 33 | "github.com/spf13/cobra" 34 | "k8s.io/apimachinery/pkg/api/errors" 35 | "k8s.io/client-go/tools/leaderelection" 36 | ) 37 | 38 | type ServerArgs struct { 39 | serverPort int 40 | serverCert string 41 | serverKey string 42 | serviceName string 43 | serviceId string 44 | serviceNamespace string 45 | selfSignCerts bool 46 | } 47 | 48 | var ( 49 | serverArgs ServerArgs 50 | ) 51 | 52 | func runCertManager(ctx context.Context) { 53 | lock, err := k8s.GetLeaseLock(serverArgs.serviceId, serverArgs.serviceName, serverArgs.serviceNamespace) 54 | common.ExitIfError(err) 55 | 56 | leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ 57 | Lock: lock, 58 | LeaseDuration: 15 * time.Second, 59 | RenewDeadline: 10 * time.Second, 60 | RetryPeriod: 2 * time.Second, 61 | Callbacks: leaderelection.LeaderCallbacks{ 62 | OnStartedLeading: onStartedLeading, 63 | OnStoppedLeading: onStoppedLeading, 64 | OnNewLeader: onNewLeader(serverArgs.serviceId), 65 | }, 66 | WatchDog: nil, 67 | ReleaseOnCancel: true, 68 | Name: serverArgs.serviceId, 69 | }) 70 | 71 | } 72 | 73 | func onStartedLeading(ctx context.Context) { 74 | common.Log.Infof("elected leader") 75 | ensureTLSCertificateSecretInCluster(ctx) 76 | for { 77 | select { 78 | case <-ctx.Done(): 79 | return 80 | case <-time.After(time.Minute): 81 | ensureTLSCertificateSecretInCluster(ctx) 82 | } 83 | } 84 | 85 | } 86 | 87 | func onStoppedLeading() { 88 | common.Log.Infof("no longer leading") 89 | } 90 | 91 | func onNewLeader(id string) func(string) { 92 | return func(newLeaderID string) { 93 | if newLeaderID != id { 94 | common.Log.Infof("%s elected new leader", newLeaderID) 95 | } 96 | } 97 | } 98 | 99 | func ensureTLSCertificateSecretInCluster(ctx context.Context) { 100 | 101 | common.Log.Infof("checking certificate %s/%s", serverArgs.serviceNamespace, serverArgs.serviceName) 102 | cert, caPem, err := k8s.GetServiceCertificate(ctx, serverArgs.serviceName, serverArgs.serviceNamespace) 103 | if err != nil && !errors.IsNotFound(err) { 104 | common.ExitIfError(err) 105 | } 106 | if cert == nil || common.ValidDaysRemaining(cert.Certificate[0]) < 30 { 107 | common.Log.Infof("Renewing self signed certificate") 108 | caPem, caKey, err := common.GenerateSelfSignedCA(serverArgs.serviceName + "-ca") 109 | common.ExitIfError(err) 110 | err = k8s.UpdateCABundleForWebhook(ctx, serverArgs.serviceName+".dhs.dockhand.dev", caPem) 111 | common.ExitIfError(err) 112 | dnsNames := []string{ 113 | serverArgs.serviceName + "." + serverArgs.serviceNamespace, 114 | serverArgs.serviceName + "." + serverArgs.serviceNamespace + ".svc"} 115 | 116 | cert, key, err := common.GenerateSignedCert(serverArgs.serviceName, dnsNames, caPem, caKey) 117 | common.ExitIfError(err) 118 | err = k8s.UpdateTlsCertificateSecret(ctx, serverArgs.serviceName, serverArgs.serviceNamespace, cert, key, caPem) 119 | common.ExitIfError(err) 120 | 121 | deploy, err := k8s.GetDeployment(ctx, serverArgs.serviceName, serverArgs.serviceNamespace) 122 | common.ExitIfError(err) 123 | checksum, err := k8s.GetSecretsChecksum(ctx, []string{serverArgs.serviceName}, serverArgs.serviceNamespace) 124 | common.ExitIfError(err) 125 | if deploy.Spec.Template.Annotations == nil { 126 | deploy.Spec.Template.Annotations = make(map[string]string) 127 | } 128 | deploy.Spec.Template.Annotations[dockhand.SecretChecksumAnnotationKey] = checksum 129 | _, err = k8s.UpdateDeployment(ctx, deploy, serverArgs.serviceNamespace) 130 | if err != nil { 131 | common.Log.Warnf("Could not update deployment %v", err) 132 | } 133 | } else { 134 | err = k8s.UpdateCABundleForWebhook(ctx, serverArgs.serviceName+".dhs.dockhand.dev", caPem) 135 | common.LogIfError(err) 136 | } 137 | 138 | } 139 | 140 | func runServer(ctx context.Context) { 141 | var err error 142 | tlsPair := tls.Certificate{} 143 | if serverArgs.selfSignCerts { 144 | leaderCtx, cancel := context.WithCancel(ctx) 145 | defer cancel() 146 | go runCertManager(leaderCtx) 147 | } else { 148 | tlsPair, err = tls.LoadX509KeyPair(serverArgs.serverCert, serverArgs.serverKey) 149 | common.ExitIfError(err) 150 | } 151 | 152 | attempt := 0 153 | for { 154 | if attempt < 10 { 155 | cert, _, err := k8s.GetServiceCertificate(ctx, serverArgs.serviceName, serverArgs.serviceNamespace) 156 | if errors.IsNotFound(err) { 157 | time.Sleep(5 * time.Second) 158 | } else if err != nil { 159 | common.Log.Warnf("error retrieving certificate, %v", err) 160 | } else { 161 | tlsPair = *cert 162 | break 163 | } 164 | attempt += 1 165 | } else { 166 | common.ExitIfError(fmt.Errorf("unable to retrieve a certificate after 10 attempts - exiting")) 167 | } 168 | } 169 | 170 | common.Log.Infof("Starting server") 171 | 172 | server := &webhook.Server{ 173 | Server: &http.Server{ 174 | Addr: fmt.Sprintf(":%v", serverArgs.serverPort), 175 | TLSConfig: &tls.Config{Certificates: []tls.Certificate{tlsPair}}, 176 | }, 177 | } 178 | 179 | server.Init() 180 | 181 | mux := http.NewServeMux() 182 | mux.HandleFunc("/mutate", server.Serve) 183 | server.Server.Handler = mux 184 | 185 | go func() { 186 | if err := server.Server.ListenAndServeTLS("", ""); err != nil { 187 | common.ExitIfError(err) 188 | } 189 | }() 190 | 191 | // listen for shutdown signal 192 | signalChan := make(chan os.Signal, 1) 193 | signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) 194 | <-signalChan 195 | 196 | common.Log.Infof("received shutdown signal, shutting down webhook gracefully") 197 | if err := server.Server.Shutdown(context.Background()); err != nil { 198 | common.Log.Infof("webhook server shutdown: %v", err) 199 | } 200 | } 201 | 202 | var startServerCmd = &cobra.Command{ 203 | Use: "server", 204 | Short: "webhook server", 205 | Long: `start the server with the provided settings`, 206 | Run: func(cmd *cobra.Command, args []string) { 207 | runServer(cmd.Context()) 208 | }, 209 | } 210 | 211 | // setup command 212 | func init() { 213 | rootCmd.AddCommand(startServerCmd) 214 | 215 | startServerCmd.Flags().StringVar( 216 | &serverArgs.serviceName, 217 | "name", 218 | "dockhand-secrets-operator-webhook", 219 | "kubernetes service name") 220 | 221 | startServerCmd.Flags().StringVar( 222 | &serverArgs.serviceNamespace, 223 | "namespace", 224 | "dockhand-secrets-operator", 225 | "kubernetes service namespace") 226 | 227 | startServerCmd.Flags().IntVar( 228 | &serverArgs.serverPort, 229 | "port", 230 | 8443, 231 | "") 232 | 233 | startServerCmd.Flags().StringVar( 234 | &serverArgs.serverCert, 235 | "cert", 236 | "/tls/server.crt", 237 | "x509 server certificate") 238 | 239 | startServerCmd.Flags().StringVar( 240 | &serverArgs.serverKey, 241 | "key", 242 | "/tls/server.key", 243 | "x509 server key") 244 | 245 | startServerCmd.Flags().StringVar( 246 | &serverArgs.serviceId, 247 | "webhook-id", 248 | "", 249 | "webhook server id") 250 | 251 | startServerCmd.Flags().BoolVar( 252 | &serverArgs.selfSignCerts, 253 | "self-sign-certs", 254 | true, 255 | "use k8s api to obtain self signed certificates") 256 | 257 | } 258 | -------------------------------------------------------------------------------- /docs/content/usage/crd-specs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CustomResourceDefinitions 3 | weight: -50 4 | --- 5 | 6 | 7 | {{< toc >}} 8 | 9 | ## Profile 10 | 11 | ``` 12 | KIND: Profile 13 | VERSION: dhs.dockhand.dev/v1alpha2 14 | 15 | DESCRIPTION: 16 | Holds configuration details for a Profile 17 | 18 | FIELDS: 19 | apiVersion 20 | APIVersion defines the versioned schema of this representation of an 21 | object. Servers should convert recognized schemas to the latest internal 22 | value, and may reject unrecognized values. More info: 23 | https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 24 | 25 | awsSecretsManager 26 | AWS Secrets Manager configuration to allow the Dockhand Secrets Operator to 27 | retrieve Secrets from AWS 28 | 29 | azureKeyVault 30 | Azure Key Vault configuration to allow the Dockhand Secrets Operator to 31 | retrieve Secrets from Azure 32 | 33 | gcpSecretsManager 34 | Google Cloud Platform Secrets Manager Configuration to allow Dockhand 35 | Secrets Operator to retrieve secrets from GCP. Authentication can be 36 | Application Default Credentials or by providing a key.json 37 | 38 | kind 39 | Kind is a string value representing the REST resource this object 40 | represents. Servers may infer this from the endpoint the client submits 41 | requests to. Cannot be updated. In CamelCase. More info: 42 | https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 43 | 44 | metadata 45 | Standard object's metadata. More info: 46 | https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata 47 | 48 | vault 49 | HashiCorp Vault Configuration to allow Dockhand Secrets Operator to 50 | retrieve secrets from Vault. Secrets can be retrieved with either a 51 | roleId/secretId or with a Vault Token. 52 | ``` 53 | 54 | ### Profile.awsSecretsManager 55 | ``` 56 | KIND: Profile 57 | VERSION: dhs.dockhand.dev/v1alpha2 58 | 59 | RESOURCE: awsSecretsManager 60 | 61 | DESCRIPTION: 62 | AWS Secrets Manager configuration to allow the Dockhand Secrets Operator to 63 | retrieve Secrets from AWS. If no accessKeyId and secretAccessKey are provided 64 | then chain credentials will be used. 65 | 66 | FIELDS: 67 | accessKeyId 68 | AWS IAM Access Key 69 | 70 | cacheTTL 71 | Duration to cache secret responses 72 | 73 | region 74 | AWS Region to retrieve secrets from 75 | 76 | secretAccessKeyRef 77 | Name of secret containing AWS IAM Secret Access Key 78 | ``` 79 | 80 | ### Profile.azureKeyVault 81 | ``` 82 | KIND: Profile 83 | VERSION: dhs.dockhand.dev/v1alpha2 84 | 85 | RESOURCE: azureKeyVault 86 | 87 | DESCRIPTION: 88 | Azure Key Vault configuration to allow the Dockhand Secrets Operator to 89 | retrieve Secrets from Azure 90 | 91 | FIELDS: 92 | cacheTTL 93 | Duration to cache secret responses 94 | 95 | clientId 96 | Azure Client ID to access the Key Vault 97 | 98 | clientSecretRef 99 | Reference to Azure Client Secret 100 | 101 | keyVault 102 | Name of Azure Key Vault to retrieve secrets from 103 | 104 | tenant 105 | Azure Tenant ID where the Key Vault resides 106 | ``` 107 | 108 | ### Profile.gcpSecretsManager 109 | ``` 110 | KIND: Profile 111 | VERSION: dhs.dockhand.dev/v1alpha2 112 | 113 | RESOURCE: gcpSecretsManager 114 | 115 | DESCRIPTION: 116 | Google Cloud Platform Secrets Manager Configuration to allow Dockhand 117 | Secrets Operator to retrieve secrets from GCP. Authentication can be 118 | Application Default Credentials or by providing a key.json 119 | 120 | FIELDS: 121 | cacheTTL 122 | Duration to cache secret responses 123 | 124 | credentialsFileSecretRef 125 | Secret Reference containing JSON credentials file stored in a key named 126 | gcp-credentials.json 127 | 128 | project 129 | The GCP Project to reference for this profile 130 | ``` 131 | 132 | ### Profile.vault 133 | ``` 134 | KIND: Profile 135 | VERSION: dhs.dockhand.dev/v1alpha2 136 | 137 | RESOURCE: vault 138 | 139 | DESCRIPTION: 140 | HashiCorp Vault Configuration to allow Dockhand Secrets Operator to 141 | retrieve secrets from Vault. Secrets can be retrieved with either a 142 | roleId/secretId or with a Vault Token. 143 | 144 | FIELDS: 145 | addr 146 | Vault Address e.g. http://vault:8200 147 | 148 | cacheTTL 149 | Duration to cache secret responses 150 | 151 | roleId 152 | Vault Role ID 153 | 154 | secretIdRef 155 | Reference to secret containing the Vault secretId 156 | 157 | tokenRef 158 | Reference to secret containing the Vault Token 159 | ``` 160 | 161 | ## Dockhand Secret 162 | ``` 163 | KIND: Secret 164 | VERSION: dhs.dockhand.dev/v1alpha2 165 | 166 | DESCRIPTION: 167 | Secret Object 168 | 169 | FIELDS: 170 | apiVersion 171 | APIVersion defines the versioned schema of this representation of an 172 | object. Servers should convert recognized schemas to the latest internal 173 | value, and may reject unrecognized values. More info: 174 | https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 175 | 176 | data 177 | Store arbitrary templated secret data here just as you would in a 178 | kubernetes configmap. The dockhand-secrets-operator will retrieve the 179 | secrets from the secrets backend and create normal kubernetes secrets for 180 | use by your application. Secrets should be templated using go templating 181 | with alternative delimiters << >> rather than \{\{ \}\}. 182 | 183 | kind 184 | Kind is a string value representing the REST resource this object 185 | represents. Servers may infer this from the endpoint the client submits 186 | requests to. Cannot be updated. In CamelCase. More info: 187 | https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 188 | 189 | metadata 190 | Standard object's metadata. More info: 191 | https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata 192 | 193 | profile 194 | Profile to use for this secret 195 | 196 | secretSpec 197 | Specification to use for creating the Kubernetes Secret 198 | 199 | status 200 | Provides basic status for a DockhandSecret 201 | 202 | syncInterval 203 | Specifies the time interval for polling the secrets backend for changes. 204 | The default value of 0 indicates that no polling will occur and is the 205 | default behavior prior to 1.1.0 release, in this case the operator will 206 | only query the backend when a field in the Dockhand Secret CRD has been 207 | modified. Valid time units are ns, us, ms, s, m, h, but must exceed 5s 208 | (when not 0). Also note that the operator will not poll the backend more 209 | frequently than the cacheTTL of the profile referenced by the Secret 210 | ``` 211 | 212 | ### Secret.secretSpec 213 | ``` 214 | KIND: Secret 215 | VERSION: dhs.dockhand.dev/v1alpha2 216 | 217 | RESOURCE: secretSpec 218 | 219 | DESCRIPTION: 220 | Specification to use for creating the Kubernetes Secret 221 | 222 | FIELDS: 223 | annotations <> 224 | Optional additional annotations to add to the secret managed by this 225 | Secret 226 | 227 | labels <> 228 | Optional additional labels to add to the secret managed by this 229 | Secret 230 | 231 | name 232 | Name of the secret that will be created or updated with the processed 233 | contents of the data field. 234 | 235 | type 236 | Type of k8s secret to create Opaque, kubernetes.io/service-account-token, 237 | kubernetes.io/dockercfg, kubernetes.io/dockerconfigjson, 238 | kubernetes.io/basic-auth, kubernetes.io/ssh-auth, kubernetes.io/tls or 239 | bootstrap.kubernetes.io/token 240 | ``` 241 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/boxboat/dockhand-secrets-operator 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/boxboat/dockcmd v1.8.7 7 | github.com/gobuffalo/packr/v2 v2.8.3 8 | github.com/mitchellh/go-homedir v1.1.0 9 | github.com/rancher/lasso v0.2.3 10 | github.com/rancher/wrangler/v3 v3.1.0 11 | github.com/sirupsen/logrus v1.9.3 12 | github.com/spf13/cobra v1.10.1 13 | github.com/spf13/viper v1.20.1 14 | k8s.io/api v0.34.0 15 | k8s.io/apimachinery v0.34.0 16 | k8s.io/client-go v0.34.0 17 | ) 18 | 19 | require ( 20 | cloud.google.com/go/auth v0.13.0 // indirect 21 | cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect 22 | cloud.google.com/go/compute/metadata v0.6.0 // indirect 23 | cloud.google.com/go/iam v1.3.0 // indirect 24 | cloud.google.com/go/secretmanager v1.14.2 // indirect 25 | dario.cat/mergo v1.0.1 // indirect 26 | github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 // indirect 27 | github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 // indirect 28 | github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect 29 | github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 // indirect 30 | github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 // indirect 31 | github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1 // indirect 32 | github.com/Masterminds/goutils v1.1.1 // indirect 33 | github.com/Masterminds/semver/v3 v3.3.1 // indirect 34 | github.com/Masterminds/sprig/v3 v3.3.0 // indirect 35 | github.com/aws/aws-sdk-go-v2 v1.32.6 // indirect 36 | github.com/aws/aws-sdk-go-v2/config v1.28.6 // indirect 37 | github.com/aws/aws-sdk-go-v2/credentials v1.17.47 // indirect 38 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 // indirect 39 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 // indirect 40 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 // indirect 41 | github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect 42 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect 43 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 // indirect 44 | github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.7 // indirect 45 | github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 // indirect 46 | github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 // indirect 47 | github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 // indirect 48 | github.com/aws/smithy-go v1.22.1 // indirect 49 | github.com/beorn7/perks v1.0.1 // indirect 50 | github.com/cenkalti/backoff/v4 v4.3.0 // indirect 51 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 52 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 53 | github.com/emicklei/go-restful/v3 v3.12.2 // indirect 54 | github.com/evanphx/json-patch v5.9.11+incompatible // indirect 55 | github.com/felixge/httpsnoop v1.0.4 // indirect 56 | github.com/fsnotify/fsnotify v1.8.0 // indirect 57 | github.com/fxamacker/cbor/v2 v2.9.0 // indirect 58 | github.com/go-jose/go-jose/v4 v4.0.5 // indirect 59 | github.com/go-logr/logr v1.4.2 // indirect 60 | github.com/go-logr/stdr v1.2.2 // indirect 61 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 62 | github.com/go-openapi/jsonreference v0.20.2 // indirect 63 | github.com/go-openapi/swag v0.23.0 // indirect 64 | github.com/go-viper/mapstructure/v2 v2.4.0 // indirect 65 | github.com/gogo/protobuf v1.3.2 // indirect 66 | github.com/golang-jwt/jwt/v5 v5.2.2 // indirect 67 | github.com/google/gnostic-models v0.7.0 // indirect 68 | github.com/google/go-cmp v0.7.0 // indirect 69 | github.com/google/s2a-go v0.1.8 // indirect 70 | github.com/google/uuid v1.6.0 // indirect 71 | github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect 72 | github.com/googleapis/gax-go/v2 v2.14.1 // indirect 73 | github.com/hashicorp/errwrap v1.1.0 // indirect 74 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 75 | github.com/hashicorp/go-multierror v1.1.1 // indirect 76 | github.com/hashicorp/go-retryablehttp v0.7.7 // indirect 77 | github.com/hashicorp/go-rootcerts v1.0.2 // indirect 78 | github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 // indirect 79 | github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect 80 | github.com/hashicorp/go-sockaddr v1.0.7 // indirect 81 | github.com/hashicorp/hcl v1.0.0 // indirect 82 | github.com/hashicorp/vault/api v1.15.0 // indirect 83 | github.com/huandu/xstrings v1.5.0 // indirect 84 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 85 | github.com/josharian/intern v1.0.0 // indirect 86 | github.com/json-iterator/go v1.1.12 // indirect 87 | github.com/kylelemons/godebug v1.1.0 // indirect 88 | github.com/mailru/easyjson v0.7.7 // indirect 89 | github.com/mitchellh/copystructure v1.2.0 // indirect 90 | github.com/mitchellh/mapstructure v1.5.0 // indirect 91 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 92 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 93 | github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect 94 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 95 | github.com/patrickmn/go-cache v2.1.0+incompatible // indirect 96 | github.com/pelletier/go-toml/v2 v2.2.3 // indirect 97 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect 98 | github.com/pkg/errors v0.9.1 // indirect 99 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 100 | github.com/prometheus/client_golang v1.22.0 // indirect 101 | github.com/prometheus/client_model v0.6.1 // indirect 102 | github.com/prometheus/common v0.62.0 // indirect 103 | github.com/prometheus/procfs v0.15.1 // indirect 104 | github.com/ryanuber/go-glob v1.0.0 // indirect 105 | github.com/sagikazarmark/locafero v0.7.0 // indirect 106 | github.com/shopspring/decimal v1.4.0 // indirect 107 | github.com/sourcegraph/conc v0.3.0 // indirect 108 | github.com/spf13/afero v1.12.0 // indirect 109 | github.com/spf13/cast v1.7.1 // indirect 110 | github.com/spf13/pflag v1.0.9 // indirect 111 | github.com/subosito/gotenv v1.6.0 // indirect 112 | github.com/x448/float16 v0.8.4 // indirect 113 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 114 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect 115 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect 116 | go.opentelemetry.io/otel v1.33.0 // indirect 117 | go.opentelemetry.io/otel/metric v1.33.0 // indirect 118 | go.opentelemetry.io/otel/trace v1.33.0 // indirect 119 | go.uber.org/multierr v1.11.0 // indirect 120 | go.yaml.in/yaml/v2 v2.4.2 // indirect 121 | go.yaml.in/yaml/v3 v3.0.4 // indirect 122 | golang.org/x/crypto v0.40.0 // indirect 123 | golang.org/x/mod v0.25.0 // indirect 124 | golang.org/x/net v0.41.0 // indirect 125 | golang.org/x/oauth2 v0.28.0 // indirect 126 | golang.org/x/sync v0.16.0 // indirect 127 | golang.org/x/sys v0.34.0 // indirect 128 | golang.org/x/term v0.33.0 // indirect 129 | golang.org/x/text v0.27.0 // indirect 130 | golang.org/x/time v0.9.0 // indirect 131 | golang.org/x/tools v0.34.0 // indirect 132 | google.golang.org/api v0.215.0 // indirect 133 | google.golang.org/genproto v0.0.0-20241209162323-e6fa225c2576 // indirect 134 | google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect 135 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect 136 | google.golang.org/grpc v1.68.1 // indirect 137 | google.golang.org/protobuf v1.36.5 // indirect 138 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 139 | gopkg.in/inf.v0 v0.9.1 // indirect 140 | gopkg.in/yaml.v3 v3.0.1 // indirect 141 | helm.sh/helm/v3 v3.18.5 // indirect 142 | k8s.io/apiextensions-apiserver v0.33.3 // indirect 143 | k8s.io/code-generator v0.33.3 // indirect 144 | k8s.io/gengo v0.0.0-20240826214909-a7b603a56eb7 // indirect 145 | k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect 146 | k8s.io/klog/v2 v2.130.1 // indirect 147 | k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect 148 | k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect 149 | sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect 150 | sigs.k8s.io/randfill v1.0.0 // indirect 151 | sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect 152 | sigs.k8s.io/yaml v1.6.0 // indirect 153 | ) 154 | --------------------------------------------------------------------------------