├── .all-contributorsrc
├── .aqua
├── aqua-policy.yaml
├── aqua.yaml
└── registry.yaml
├── .changes
├── header.tpl.md
├── unreleased
│ ├── .gitkeep
│ └── new-product-feature-20250220-181256.yaml
├── v1.0.1.md
├── v1.1.0.md
├── v1.1.1.md
├── v1.1.2.md
├── v1.1.3.md
├── v1.1.4.md
├── v1.1.5.md
├── v1.1.6.md
├── v1.2.0.md
├── v1.2.1.md
├── v1.2.2.md
├── v1.2.3.md
└── v1.2.4.md
├── .changie.yaml
├── .devcontainer
├── Dockerfile
├── devcontainer.json
├── files
│ ├── .zshrc
│ └── first-run-notice.txt
├── init
└── init.bat
├── .editorconfig
├── .envrc
├── .gitattributes
├── .github
├── CODEOWNERS
├── auto-assign.yml
└── workflows
│ ├── assign.yml
│ ├── changie-trigger-release.yml
│ ├── conventional-pr.yml
│ ├── lint.yml
│ ├── release-composite.yml
│ ├── release.yml
│ ├── scan.yml
│ ├── stale.yaml
│ └── test.yml
├── .gitignore
├── .gitleaks.toml
├── .golangci.yml
├── .goreleaser.yaml
├── .hadolint.yaml
├── .idea
├── .gitignore
├── dsv-k8s.iml
├── inspectionProfiles
│ └── Project_Default.xml
├── markdown.xml
├── modules.xml
└── vcs.xml
├── .markdownlint.yaml
├── .npmrc
├── .pre-commit-config.yaml
├── .prettierrc.yaml
├── .shellcheckrc
├── .snyk
├── .trunk
├── .gitignore
└── trunk.yaml
├── .vscode
├── settings.json
└── tasks.json
├── .whitesource
├── .yamllint.yaml
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── Makefile
├── Makefile.helpers
├── README.md
├── Tiltfile
├── charts
├── dsv-injector
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── README.md
│ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── configmap.yaml
│ │ ├── credentials-secret.yaml
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── webhook.yaml
│ └── values.yaml
└── dsv-syncer
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── README.md
│ ├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── cluster-role-binding.yaml
│ ├── cluster-role.yaml
│ ├── configmap.yaml
│ ├── serviceaccount.yaml
│ └── syncer-cronjob.yaml
│ └── values.yaml
├── cmd
├── injector
│ └── main.go
└── syncer
│ └── main.go
├── codecov.yml
├── docker
├── Dockerfile.chainguard
├── Dockerfile.distroless
└── Dockerfile.scratch
├── docs
├── assets
│ ├── info-markup-default-creds.svg
│ ├── random-dont-need-to-install.svg
│ └── warning-app1-required-for-tests.svg
├── configure.md
├── devcontainer.md
├── developer-debugging.md
├── developer-reference.md
├── helm-install.md
├── local-cli-invoke.md
├── local-kubernetes.md
├── local-testing.md
├── release.md
├── setup-developer.md
├── setup-project.md
├── troubleshooting.md
└── using.md
├── examples
├── add-to-secret.yml
├── set-secret.yml
└── update-secret.yml
├── go.mod
├── go.sum
├── internal
├── k8s
│ └── k8s.go
├── logger
│ └── logger.go
└── test
│ └── testing.go
├── magefiles
├── constants
│ ├── constants.mage.go
│ └── variables.mage.go
├── dev-cli-tools.go
├── goreleaser.mage.go
├── helm
│ └── helm.mage.go
├── install.mage.go
├── jobs.mage.go
├── k8s
│ └── k8s.mage.go
├── kind-3-nodes.yaml
├── kind
│ └── kind.mage.go
├── mage.go
├── magefile.go
├── minikube
│ └── minikube.mage.go
└── vault
│ └── vault.mage.go
├── pkg
├── config
│ ├── credentials.go
│ └── credentials_test.go
├── injector
│ └── inject.go
├── patch
│ ├── patch.go
│ └── patch_test.go
└── syncer
│ └── sync.go
└── renovate.json
/.all-contributorsrc:
--------------------------------------------------------------------------------
1 | {
2 | "files": [
3 | "README.md"
4 | ],
5 | "imageSize": 100,
6 | "commit": false,
7 | "commitConvention": "angular",
8 | "contributors": [
9 | {
10 | "login": "amigus",
11 | "name": "Adam C. Migus",
12 | "avatar_url": "https://avatars.githubusercontent.com/u/119477?v=4",
13 | "profile": "https://mig.us/adam",
14 | "contributions": [
15 | "code",
16 | "doc",
17 | "test"
18 | ]
19 | },
20 | {
21 | "login": "hansboder",
22 | "name": "Hans Boder",
23 | "avatar_url": "https://avatars.githubusercontent.com/u/36736535?v=4",
24 | "profile": "https://github.com/hansboder",
25 | "contributions": [
26 | "bug"
27 | },
28 | {
29 | "login": "sheldonhull",
30 | "name": "sheldonhull",
31 | "avatar_url": "https://avatars.githubusercontent.com/u/3526320?v=4",
32 | "profile": "https://www.sheldonhull.com",
33 | "contributions": [
34 | "code",
35 | "doc",
36 | "test"
37 | ]
38 | },
39 | {
40 | "login": "tylerezimmerman",
41 | "name": "tylerezimmerman",
42 | "avatar_url": "https://avatars.githubusercontent.com/u/100804646?v=4",
43 | "profile": "https://github.com/tylerezimmerman",
44 | "contributions": [
45 | "maintenance"
46 | ]
47 | },
48 | {
49 | "login": "delineaKrehl",
50 | "name": "Tim Krehl",
51 | "avatar_url": "https://avatars.githubusercontent.com/u/105234788?v=4",
52 | "profile": "https://github.com/delineaKrehl",
53 | "contributions": [
54 | "maintenance"
55 | ]
56 | },
57 | {
58 | "login": "EndlessTrax",
59 | "name": "Ricky White",
60 | "avatar_url": "https://avatars.githubusercontent.com/u/17141891?v=4",
61 | "profile": "http://endlesstrax.com",
62 | "contributions": [
63 | "maintenance"
64 | ]
65 | },
66 | {
67 | "login": "forced-request",
68 | "name": "John Poulin",
69 | "avatar_url": "https://avatars.githubusercontent.com/u/961246?v=4",
70 | "profile": "https://github.com/forced-request",
71 | "contributions": [
72 | "maintenance"
73 | ]
74 | }
75 | ],
76 | "contributorsPerLine": 7,
77 | "skipCi": true,
78 | "repoType": "github",
79 | "repoHost": "https://github.com",
80 | "projectName": "dsv-k8s",
81 | "projectOwner": "DelineaXPM"
82 | }
83 |
--------------------------------------------------------------------------------
/.aqua/aqua-policy.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # aqua Policy
3 | # https://aquaproj.github.io/
4 | registries:
5 | - type: standard
6 | ref: semver(">= 3.0.0")
7 | - name: local
8 | type: local
9 | path: registry.yaml
10 | packages:
11 | - registry: standard
12 | - registry: local
13 |
--------------------------------------------------------------------------------
/.aqua/aqua.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # aqua - Declarative CLI Version Manager
3 | # https://aquaproj.github.io/
4 | checksum:
5 | enabled: false
6 | require_checksum: false
7 | registries:
8 | - type: standard
9 | ref: v4.212.0 # renovate: depName=aquaproj/aqua-registry
10 | - name: local
11 | type: local
12 | path: registry.yaml
13 | packages:
14 | - name: miniscruff/changie@v1.19.1
15 | tags: ['release']
16 | - name: golang/go@go1.22.6
17 | tags: ['first', 'release', 'test', 'scan', 'lint']
18 | - name: direnv/direnv@v2.34.0
19 | - name: magefile/mage@v1.15.0
20 | tags: ['release', 'test', 'scan', 'lint']
21 | - name: charmbracelet/glow@v1.5.1
22 | - name: goreleaser/goreleaser@v2.1.0
23 | tags: ['release']
24 | - name: mvdan/gofumpt@v0.6.0
25 | - name: anchore/syft@v1.11.0
26 | tags: ['release']
27 | - name: norwoodj/helm-docs@v1.14.2
28 | - name: gotestyourself/gotestsum@v1.12.0
29 | tags: ['test']
30 | - name: c-bata/kube-prompt@v1.0.11
31 | - name: kubernetes-sigs/kind@v0.23.0
32 | - name: kubernetes/kubectl
33 | version: v1.25.2
34 | - name: helm/helm@v3.15.3
35 | - name: kubernetes/minikube@v1.33.1
36 | tags: ['ci']
37 | - name: stern/stern@v1.30.0
38 | - name: tilt-dev/tilt@v0.33.19
39 | - name: golangci/golangci-lint@v1.59.1
40 | tags: ['lint']
41 | - name: mage-select
42 | version: v1.4.2
43 | registry: local
44 | tags: ['goinstall']
45 | - name: DelineaXPM/dsv-cli@v1.41.1
46 | - name: gitleaks/gitleaks@v8.18.4
47 | - name: charmbracelet/gum@v0.14.3
48 | - name: cli/cli@v2.58.0
49 | tags:
50 | - release
51 | - name: miniscruff/changie@v1.21.0
52 | - name: mikefarah/yq@v4.44.3
53 | tags:
54 | - release
55 |
--------------------------------------------------------------------------------
/.aqua/registry.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | packages:
3 | - type: go_install
4 | name: mage-select
5 | path: github.com/iwittkau/mage-select
6 | link: github.com/iwittkau/mage-select
7 | description: CLI frontend for mage based on promptui.
8 | search_words:
9 | - mage
10 | - module
11 | - go
12 | - prompt
13 |
--------------------------------------------------------------------------------
/.changes/header.tpl.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
7 | and is generated by [Changie](https://github.com/miniscruff/changie).
8 |
--------------------------------------------------------------------------------
/.changes/unreleased/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DelineaXPM/dsv-k8s/86bfd49799fe18bd5745d195a52c525926e5857a/.changes/unreleased/.gitkeep
--------------------------------------------------------------------------------
/.changes/unreleased/new-product-feature-20250220-181256.yaml:
--------------------------------------------------------------------------------
1 | kind: new-product-feature
2 | body: Added documentation to utilize Azure Entra authentication
3 | time: 2025-02-20T18:12:56.436354904Z
4 |
--------------------------------------------------------------------------------
/.changes/v1.1.0.md:
--------------------------------------------------------------------------------
1 | ## [v1.1.0] (2022-10-10)
2 |
3 | ### Added
4 |
5 | - feat: Configure Mend for GitHub.com (#26) (2022-08-26)
6 |
7 | ### Fixed
8 |
9 | - fix(mend): 🐛 remove trailing space in json (2022-08-26)
10 | - fix(tests): 🧪 resolve failing test cases and improve local testing automation (#7) (2022-07-27)
11 |
12 | ### Others
13 |
14 | - chore(deps): update trunk-io/trunk-action digest to 22e948f (#59) (2022-10-07)
15 | - chore(deps): update actions/stale digest to 5ebf00e (#58) (2022-10-07)
16 | - chore: add trunk config checks as linting tool (#40) (2022-10-07)
17 | - chore(deps): update amannn/action-semantic-pull-request digest to 505e44b (#46) (2022-09-28)
18 | - docs: add forced-request as a contributor for maintenance (#53) (2022-09-28)
19 | - docs: add EndlessTrax as a contributor for maintenance (#52) (2022-09-28)
20 | - docs: add delineaKrehl as a contributor for maintenance (#51) (2022-09-27)
21 | - docs: add tylerezimmerman as a contributor for maintenance (#50) (2022-09-27)
22 | - docs: add sheldonhull as a contributor for code, doc, and test (#48) (2022-09-27)
23 | - docs: add hansboder as a contributor for bug (#54) (2022-09-27)
24 | - docs: add amigus as a contributor for code, doc, and test (#49) (2022-09-27)
25 | - chore(deps): update actions/stale action to v6 (#43) (2022-09-27)
26 | - chore(deps): update actions/stale digest to 9c1b1c6 (#38) (2022-09-01)
27 | - chore(vscode): add missing linting settings (2022-09-01)
28 | - chore: align github workflows and tooling (#37) (2022-09-01)
29 | - ci(action/docker): 🔨 eliminate github event name push from skipping workflow dispatch (2022-08-31)
30 | - chore(deps): update kentaro-m/auto-assign-action action to v1.2.3 (#35) (2022-08-31)
31 | - chore(deps): update kentaro-m/auto-assign-action action to v1.2.2 (#34) (2022-08-29)
32 | - chore(deps): update kubernetes packages to v0.25.0 (#25) (2022-08-26)
33 | - ci(mend): disable issues for mend but still allow pull and renovate execution (2022-08-26)
34 | - chore(deps): update github.com/mattbaird/jsonpatch digest to 098863c (#13) (2022-08-23)
35 | - chore: update maintainers (#24) (2022-08-23)
36 | - chore(devcontainer): 🧰 improvements to experience with setup directions, prebuilt tooling, and reliability (#23) (2022-08-20)
37 | - chore(deps): update kubernetes packages to v0.24.4 (#22) (2022-08-18)
38 | - ci(tests): fix name of tasks (2022-08-05)
39 | - chore(deps): update ⬆️ golang module go to 1.19 (#17) (2022-08-05)
40 | - ci(tests): remove push filter condition (2022-08-05)
41 | - ci(tests): use mage to run tests (2022-08-05)
42 | - ci(tests): 🔨 adjust test to use gotestsum (2022-08-05)
43 | - ci(tests): ➕ require tests to be run as part of pull request (2022-08-05)
44 | - ci: 🤖 add workflow dispatch to docker building actions (#21) (2022-08-03)
45 | - ci(docker): set registry as org secret (#20) (2022-08-01)
46 | - chore: use new env vars for docker hub publishing (#19) (2022-08-01)
47 | - chore(deps): update ⬆️ golang module github.com/pterm/pterm to v0.12.45 (#16) [skip ci] (2022-07-29)
48 | - chore(deps): update ⬆️ golang module github.com/mittwald/go-helm-client to v0.11.3 (#14) [skip ci] (2022-07-28)
49 | - Configure Renovate AB#449139 (#11) (2022-07-28)
50 | - chore(codeowner): assign default codeowners (#12) (2022-07-27)
51 | - chore(helm): ⬆️ bump chart patch version due to minor changes (#8) (2022-07-27)
52 | - Merge pull request #6 from The-Migus-Group/fix-meta (2022-07-12)
53 | - Merge pull request #5 from DelineaXPM/fix-docker (2022-06-28)
54 | - Merge pull request #4 from DelineaXPM/fix-3 (2022-06-28)
55 | - Merge pull request #1 from DelineaXPM/delineaKrehl-DeepRebrand (2022-06-02)
56 | - Fix for #13 that improves injector error handling. (#14) (2022-05-20)
57 | - Add Testing 📛 (2022-05-06)
58 | - Run go test ./... (2022-05-06)
59 | - Shorten the name of the github action (2022-05-06)
60 | - Fix build badges. 📛 (2022-05-06)
61 | - Secret Synchronization Mechanism #11 (#12) (2022-05-06)
62 | - Merge pull request #10 from thycotic/chart-upgrade-fixes (2022-03-22)
63 | - Eval role logic after patchMode test; Fixes #8 (#9) (2022-03-10)
64 | - Comments + all = install-image (2022-03-01)
65 | - Publish to Minikube by default. 🪄 (2022-03-01)
66 |
--------------------------------------------------------------------------------
/.changes/v1.1.1.md:
--------------------------------------------------------------------------------
1 | ## [v1.1.1] (2022-10-10)
2 |
3 | ### Added
4 |
5 | - feat: Configure Mend for GitHub.com (#26) (2022-08-26)
6 |
7 | ### Fixed
8 |
9 | - fix(mend): 🐛 remove trailing space in json (2022-08-26)
10 | - fix(tests): 🧪 resolve failing test cases and improve local testing automation (#7) (2022-07-27)
11 |
12 | ### Others
13 |
14 | - chore(deps): update trunk-io/trunk-action digest to 22e948f (#59) (2022-10-07)
15 | - chore(deps): update actions/stale digest to 5ebf00e (#58) (2022-10-07)
16 | - chore: add trunk config checks as linting tool (#40) (2022-10-07)
17 | - chore(deps): update amannn/action-semantic-pull-request digest to 505e44b (#46) (2022-09-28)
18 | - docs: add forced-request as a contributor for maintenance (#53) (2022-09-28)
19 | - docs: add EndlessTrax as a contributor for maintenance (#52) (2022-09-28)
20 | - docs: add delineaKrehl as a contributor for maintenance (#51) (2022-09-27)
21 | - docs: add tylerezimmerman as a contributor for maintenance (#50) (2022-09-27)
22 | - docs: add sheldonhull as a contributor for code, doc, and test (#48) (2022-09-27)
23 | - docs: add hansboder as a contributor for bug (#54) (2022-09-27)
24 | - docs: add amigus as a contributor for code, doc, and test (#49) (2022-09-27)
25 | - chore(deps): update actions/stale action to v6 (#43) (2022-09-27)
26 | - chore(deps): update actions/stale digest to 9c1b1c6 (#38) (2022-09-01)
27 | - chore(vscode): add missing linting settings (2022-09-01)
28 | - chore: align github workflows and tooling (#37) (2022-09-01)
29 | - ci(action/docker): 🔨 eliminate github event name push from skipping workflow dispatch (2022-08-31)
30 | - chore(deps): update kentaro-m/auto-assign-action action to v1.2.3 (#35) (2022-08-31)
31 | - chore(deps): update kentaro-m/auto-assign-action action to v1.2.2 (#34) (2022-08-29)
32 | - chore(deps): update kubernetes packages to v0.25.0 (#25) (2022-08-26)
33 | - ci(mend): disable issues for mend but still allow pull and renovate execution (2022-08-26)
34 | - chore(deps): update github.com/mattbaird/jsonpatch digest to 098863c (#13) (2022-08-23)
35 | - chore: update maintainers (#24) (2022-08-23)
36 | - chore(devcontainer): 🧰 improvements to experience with setup directions, prebuilt tooling, and reliability (#23) (2022-08-20)
37 | - chore(deps): update kubernetes packages to v0.24.4 (#22) (2022-08-18)
38 | - ci(tests): fix name of tasks (2022-08-05)
39 | - chore(deps): update ⬆️ golang module go to 1.19 (#17) (2022-08-05)
40 | - ci(tests): remove push filter condition (2022-08-05)
41 | - ci(tests): use mage to run tests (2022-08-05)
42 | - ci(tests): 🔨 adjust test to use gotestsum (2022-08-05)
43 | - ci(tests): ➕ require tests to be run as part of pull request (2022-08-05)
44 | - ci: 🤖 add workflow dispatch to docker building actions (#21) (2022-08-03)
45 | - ci(docker): set registry as org secret (#20) (2022-08-01)
46 | - chore: use new env vars for docker hub publishing (#19) (2022-08-01)
47 | - chore(deps): update ⬆️ golang module github.com/pterm/pterm to v0.12.45 (#16) [skip ci] (2022-07-29)
48 | - chore(deps): update ⬆️ golang module github.com/mittwald/go-helm-client to v0.11.3 (#14) [skip ci] (2022-07-28)
49 | - Configure Renovate AB#449139 (#11) (2022-07-28)
50 | - chore(codeowner): assign default codeowners (#12) (2022-07-27)
51 | - chore(helm): ⬆️ bump chart patch version due to minor changes (#8) (2022-07-27)
52 | - Merge pull request #6 from The-Migus-Group/fix-meta (2022-07-12)
53 | - Merge pull request #5 from DelineaXPM/fix-docker (2022-06-28)
54 | - Merge pull request #4 from DelineaXPM/fix-3 (2022-06-28)
55 | - Merge pull request #1 from DelineaXPM/delineaKrehl-DeepRebrand (2022-06-02)
56 | - Fix for #13 that improves injector error handling. (#14) (2022-05-20)
57 | - Add Testing 📛 (2022-05-06)
58 | - Run go test ./... (2022-05-06)
59 | - Shorten the name of the github action (2022-05-06)
60 | - Fix build badges. 📛 (2022-05-06)
61 | - Secret Synchronization Mechanism #11 (#12) (2022-05-06)
62 | - Merge pull request #10 from thycotic/chart-upgrade-fixes (2022-03-22)
63 | - Eval role logic after patchMode test; Fixes #8 (#9) (2022-03-10)
64 |
--------------------------------------------------------------------------------
/.changes/v1.1.2.md:
--------------------------------------------------------------------------------
1 | ## [v1.1.2] (2022-10-10)
2 |
3 | ### Added
4 |
5 | - feat: Configure Mend for GitHub.com (#26) (2022-08-26)
6 |
7 | ### Fixed
8 |
9 | - fix(mend): 🐛 remove trailing space in json (2022-08-26)
10 | - fix(tests): 🧪 resolve failing test cases and improve local testing automation (#7) (2022-07-27)
11 |
12 | ### Others
13 |
14 | - chore(deps): update trunk-io/trunk-action digest to 22e948f (#59) (2022-10-07)
15 | - chore(deps): update actions/stale digest to 5ebf00e (#58) (2022-10-07)
16 | - chore: add trunk config checks as linting tool (#40) (2022-10-07)
17 | - chore(deps): update amannn/action-semantic-pull-request digest to 505e44b (#46) (2022-09-28)
18 | - docs: add forced-request as a contributor for maintenance (#53) (2022-09-28)
19 | - docs: add EndlessTrax as a contributor for maintenance (#52) (2022-09-28)
20 | - docs: add delineaKrehl as a contributor for maintenance (#51) (2022-09-27)
21 | - docs: add tylerezimmerman as a contributor for maintenance (#50) (2022-09-27)
22 | - docs: add sheldonhull as a contributor for code, doc, and test (#48) (2022-09-27)
23 | - docs: add hansboder as a contributor for bug (#54) (2022-09-27)
24 | - docs: add amigus as a contributor for code, doc, and test (#49) (2022-09-27)
25 | - chore(deps): update actions/stale action to v6 (#43) (2022-09-27)
26 | - chore(deps): update actions/stale digest to 9c1b1c6 (#38) (2022-09-01)
27 | - chore(vscode): add missing linting settings (2022-09-01)
28 | - chore: align github workflows and tooling (#37) (2022-09-01)
29 | - ci(action/docker): 🔨 eliminate github event name push from skipping workflow dispatch (2022-08-31)
30 | - chore(deps): update kentaro-m/auto-assign-action action to v1.2.3 (#35) (2022-08-31)
31 | - chore(deps): update kentaro-m/auto-assign-action action to v1.2.2 (#34) (2022-08-29)
32 | - chore(deps): update kubernetes packages to v0.25.0 (#25) (2022-08-26)
33 | - ci(mend): disable issues for mend but still allow pull and renovate execution (2022-08-26)
34 | - chore(deps): update github.com/mattbaird/jsonpatch digest to 098863c (#13) (2022-08-23)
35 | - chore: update maintainers (#24) (2022-08-23)
36 | - chore(devcontainer): 🧰 improvements to experience with setup directions, prebuilt tooling, and reliability (#23) (2022-08-20)
37 | - chore(deps): update kubernetes packages to v0.24.4 (#22) (2022-08-18)
38 | - ci(tests): fix name of tasks (2022-08-05)
39 | - chore(deps): update ⬆️ golang module go to 1.19 (#17) (2022-08-05)
40 | - ci(tests): remove push filter condition (2022-08-05)
41 | - ci(tests): use mage to run tests (2022-08-05)
42 | - ci(tests): 🔨 adjust test to use gotestsum (2022-08-05)
43 | - ci(tests): ➕ require tests to be run as part of pull request (2022-08-05)
44 | - ci: 🤖 add workflow dispatch to docker building actions (#21) (2022-08-03)
45 | - ci(docker): set registry as org secret (#20) (2022-08-01)
46 | - chore: use new env vars for docker hub publishing (#19) (2022-08-01)
47 | - chore(deps): update ⬆️ golang module github.com/pterm/pterm to v0.12.45 (#16) [skip ci] (2022-07-29)
48 | - chore(deps): update ⬆️ golang module github.com/mittwald/go-helm-client to v0.11.3 (#14) [skip ci] (2022-07-28)
49 | - Configure Renovate AB#449139 (#11) (2022-07-28)
50 | - chore(codeowner): assign default codeowners (#12) (2022-07-27)
51 | - chore(helm): ⬆️ bump chart patch version due to minor changes (#8) (2022-07-27)
52 | - Merge pull request #6 from The-Migus-Group/fix-meta (2022-07-12)
53 | - Merge pull request #5 from DelineaXPM/fix-docker (2022-06-28)
54 | - Merge pull request #4 from DelineaXPM/fix-3 (2022-06-28)
55 | - Merge pull request #1 from DelineaXPM/delineaKrehl-DeepRebrand (2022-06-02)
56 | - Fix for #13 that improves injector error handling. (#14) (2022-05-20)
57 | ]
58 |
--------------------------------------------------------------------------------
/.changes/v1.1.3.md:
--------------------------------------------------------------------------------
1 | ## v1.1.3 - 2022-10-10
2 |
3 | ### Added
4 |
5 | - Changelog generation triggers docker release instead of every commit
6 |
7 | ### Fixed
8 |
9 | - Resolve dockerhub publishing.
10 |
--------------------------------------------------------------------------------
/.changes/v1.1.4.md:
--------------------------------------------------------------------------------
1 | ## v1.1.4 - 2022-10-11
2 |
3 | ### Security
4 |
5 | Update kubernetes package dependencies.
6 |
--------------------------------------------------------------------------------
/.changes/v1.1.5.md:
--------------------------------------------------------------------------------
1 | ## v1.1.5 - 2023-01-24
2 |
3 | ### 🔨 Refactor
4 |
5 | - Point the helm charts towards docker hub based images, instead of quay, as these are now iterated on with changelog driven release instead of each commit.
6 | This should reduce frequency of needless version updates.
7 |
8 | ### 🐛 Bug Fix
9 |
10 | - Docker Hub published images did not have the correct path to the injector and syncer, resulting in an invalid entrypoint.
11 | This is fixed and should now correctly resolve when using the updated helm charts that provide a qualified path.
12 | For example: `/app/dsv-injector` instead of just saying `dsv-injector` now.
13 | This is due to using a minimal distroless image and not copying binaries into a path that is assumed to be resolved automatically by `PATH`, such as `/usr/local/bin`.
14 | Now the path to the binary is explicitly set and should resolve any path resolution issues.
15 |
16 | ### 🤖 Development
17 |
18 | - Bump aqua tooling and include dsv-cli in the project setup.
19 | - Included `CGO_ENABLED=0` to avoid issues with running commands in devcontainers & codespaces.
20 | - Improved mage tasks to support minikube as default to see if this helps with Codespace timeouts being experienced.
21 | - Bumped the docker feature kit to 2.0 as well to attempt to resolve timeouts in devcontainer/codespaces.
22 |
23 | ### Related
24 |
25 | - fixes AB#483421
26 | - [Issue 83 Fixed](https://github.com/DelineaXPM/dsv-k8s/issues/83).
27 | Thank you @JulianPedro for helping identify this and opening the descriptive issue. 👍
28 |
29 | ### Contributors
30 |
31 | - [sheldonhull](https://github.com/sheldonhull)
32 |
--------------------------------------------------------------------------------
/.changes/v1.1.6.md:
--------------------------------------------------------------------------------
1 | ## v1.1.6 - 2023-02-06
2 |
3 | ### 🤖 CI
4 |
5 | - Adjust Quay registry to be a target publishing platform instead of building on every single commit to main.
6 | This aligns Quay registry with the more controlled semver versioning in docker hub instead of publishing under latest only.
7 |
8 | ### Related
9 |
10 | - fixed AB#485565
11 |
12 | ### Contributors
13 |
14 | - [sheldonhull](https://github.com/sheldonhull)
15 |
--------------------------------------------------------------------------------
/.changes/v1.2.0.md:
--------------------------------------------------------------------------------
1 | ## v1.2.0 - 2023-04-27
2 |
3 | ### 🤖 CI & Build
4 |
5 | - Improve mage tasks for minikube, including list images, remove/load images.
6 | - Update aqua to the latest version.
7 | - Include aqua configuration tags for Github actions.
8 | - Pin the version examples in the chart install and yaml values file as a better practice for production chart usage.
9 | - Chart versions no longer are independently versioned.
10 | Instead the docker image, syncing chart, and injector chart are all aligned with the same version number.
11 | This is automatically kept to the correct version when running `changie merge`.
12 |
13 | ### 🔨 Refactor
14 |
15 | - Improve output to structured json logs.
16 | - Change invocation to use environment variable configuration.
17 | - Allow users to provide config maps dynamically in Values.yaml.
18 | - Note the current version, commit sha, and date of the currently used binary at startup.
19 |
20 | ### 🔒 Security
21 |
22 | - Improve the base image to use Chainguard's static nonroot image.
23 | - Ensure default timeout is set for `ReadHeaderTimeout`.
24 |
25 | ### 🤖 Development
26 |
27 | - Improve the local development experience with Tilt.
28 | - Improve documentation and include stern/kubectl log to file snippets.
29 | - Add local development checks for values files.
30 | This will catch incorrectly configured values that are difficult to troubleshoot in local development workflows.
31 | - Add missing `--overwrite` tag to `mage minikube:loadimages` task.
--------------------------------------------------------------------------------
/.changes/v1.2.1.md:
--------------------------------------------------------------------------------
1 | ## v1.2.1 - 2023-09-05
2 |
3 | ### 📘 Documentation
4 |
5 | - Include detail on providing `tld` in the configuration, allowing `eu` and other TLDs to be used.
6 | - Mention `tilt up` in the initial setup config as viable option.
7 |
8 | ### 🤖 CI & Build
9 |
10 | - Improve mage tasks with secret setup and tear down for better development support and troubleshooting.
11 | - Bump go version in release pipeline to use `1.21` as can include standard library security improvements.
12 | - Remove failing error condition on `mage job:rebuild` to better allow default setup without running local builds, such as just using the published docker image.
13 | This supports easier demo/test usage by support.
14 |
15 | ### 🔨 Refactor
16 |
17 | - Improve logging with error wrapping and remove deprecated Go `ioutil` usage.
18 |
19 | ### ⬆️ Dependencies
20 |
21 | - Bump tooling such as changie, release, trunk, more security scanners.
22 | - Other dependency bumps such as `golang.org/x/net`.
23 |
--------------------------------------------------------------------------------
/.changes/v1.2.2.md:
--------------------------------------------------------------------------------
1 | ## v1.2.2 - 2024-01-15
2 |
3 |
4 | ### ⬆️ Dependencies
5 |
6 | - Update dependent libraries and go version. No user facing changes, just continued maintenance for improved security & stability.
--------------------------------------------------------------------------------
/.changes/v1.2.3.md:
--------------------------------------------------------------------------------
1 | ## v1.2.3 - 2024-08-12
2 |
3 |
4 | ### 🤖 CI & Build
5 |
6 | - Add a buildName metadata to binary so easy to see if caching issue with container loading. Handle `dev.local/dsv-k8s` as standard image name to better reflect standard approach I've been using. Improve validation checks. Goreleaser upgrade schema and more. Lots of quality of life improvements for dev, and aqua updates.
7 |
8 | ### 🔨 Refactor
9 |
10 | - Improve `values.yml` for the dsv-injector to expose the days till expiration of the self signed cert.
11 | Include minor doc improvements to this as well to better handle.
--------------------------------------------------------------------------------
/.changes/v1.2.4.md:
--------------------------------------------------------------------------------
1 | ## v1.2.4 - 2024-10-02
2 |
3 |
4 | ### 🤖 CI & Build
5 |
6 | - Improve mage tasks and linting with fixes. Less issues with err output on cleanup now, and also load the docker version of images into minikube setup proactively.
7 |
8 | ### ⬆️ Dependencies
9 |
10 | - Maintenance release due to updated dependencies.
--------------------------------------------------------------------------------
/.changie.yaml:
--------------------------------------------------------------------------------
1 | changesDir: .changes
2 | unreleasedDir: unreleased
3 | headerPath: header.tpl.md
4 | changelogPath: CHANGELOG.md
5 | versionExt: md
6 | versionFormat: '## {{.Version}} - {{.Time.Format "2006-01-02"}}'
7 | kindFormat: ''
8 | changeFormat: '- _{{ .KindLabel }}_: {{ .Body -}}'
9 | body:
10 | block: true
11 | kinds:
12 | - label: 🤖 CI & Build
13 | auto: patch
14 | key: ci-build
15 | - label: 🎉 New Product Feature
16 | auto: minor
17 | key: new-product-feature
18 | - label: ⬇️ Deprecated
19 | auto: minor
20 | key: deprecated
21 | - label: 🧪 Tests
22 | auto: patch
23 | key: tests
24 | - label: 🔨 Refactor
25 | auto: patch
26 | key: refactor
27 | - label: 🐛 Bug Fix
28 | auto: patch
29 | key: bug-fix
30 | - label: 🔥 Breaking Change
31 | auto: minor
32 | key: breaking-change
33 | - label: 🔒 Security
34 | auto: patch
35 | key: security
36 | - label: ⬆️ Dependencies
37 | auto: patch
38 | key: dependencies
39 | - label: 🔥 Major Version Change (Breaking Changes)
40 | auto: major
41 | key: major-version-change
42 | newlines:
43 | afterChange: 0
44 | afterChangelogHeader: 1
45 | afterChangelogVersion: 1
46 | afterComponent: 1
47 | afterFooterFile: 1
48 | afterFooter: 1
49 | afterHeaderFile: 1
50 | afterHeaderTemplate: 1
51 | afterKind: 1
52 | afterVersion: 1
53 |
54 | beforeChange: 0
55 | beforeChangelogVersion: 0
56 | beforeComponent: 0
57 | beforeFooterFile: 0
58 | beforeFooterTemplate: 0
59 | beforeHeaderFile: 0
60 | beforeHeaderTemplate: 0
61 | beforeKind: 1
62 | beforeVersion: 0
63 | endOfVersion: 0
64 |
65 | replacements:
66 | # chart versions align with the release and get bumped by changie for us on `changie merge`.
67 | - path: 'charts/dsv-injector/Chart.yaml'
68 | find: 'version: .*'
69 | replace: 'version: {{.Version}}'
70 | - path: 'charts/dsv-syncer/Chart.yaml'
71 | find: 'version: .*'
72 | replace: 'version: {{.Version}}'
73 | # use pinned versions in the chart install examples as a best practice
74 | - path: 'charts/dsv-injector/Chart.yaml'
75 | find: "IMAGE_TAG='.*'"
76 | replace: "IMAGE_TAG='{{.Version}}'"
77 | - path: 'charts/dsv-syncer/Chart.yaml'
78 | find: "IMAGE_TAG='.*'"
79 | replace: "IMAGE_TAG='{{.Version}}'"
80 | # use pinned versions in the chart default values as a best practice
81 | - path: 'charts/dsv-injector/values.yaml'
82 | find: 'tag: .*'
83 | replace: 'tag: {{.Version}}'
84 | - path: 'charts/dsv-syncer/values.yaml'
85 | find: 'tag: .*'
86 | replace: 'tag: {{.Version}}'
87 |
--------------------------------------------------------------------------------
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/devcontainers/base:bullseye
2 | # BUILD ARGS FROM DEVCONTAINER JSON
3 | ARG DEVCONTAINER_USER
4 | ARG GOPATH
5 |
6 | USER root
7 | ENV DOCKER_BUILDKIT=1
8 | ENV GOPATH=$GOPATH
9 | # to avoid gcc compile issues as don't need gcc except for race conditions testing
10 | ENV CGO_ENABLED=0
11 | ENV MAGEFILE_ENABLE_COLOR=1
12 | ENV TRUNK_LAUNCHER_QUIET=true
13 | ENV PATH="$GOPATH/bin:/home/$DEVCONTAINER_USER/.local/share/aquaproj-aqua/bin:/home/$DEVCONTAINER_USER/go/bin:$PATH"
14 | # ENV PATH="${GOPATH}/bin:${PATH}" --> this uses HOST path , use the $PATH variable instead
15 | USER $DEVCONTAINER_USER
16 | COPY files/.zshrc /home/$DEVCONTAINER_USER/.zshrc
17 | COPY files/first-run-notice.txt /home/$DEVCONTAINER_USER/first-run-notice.txt
18 |
19 | RUN mkdir -p /home/$DEVCONTAINER_USER/.minikube \
20 | && sudo chown $DEVCONTAINER_USER /home/$DEVCONTAINER_USER/.minikube \
21 | && mkdir -p /home/$DEVCONTAINER_USER/go \
22 | && sudo chown $DEVCONTAINER_USER /home/$DEVCONTAINER_USER/go \
23 | && /bin/bash -c 'set -euo pipefail && curl https://get.trunk.io -fsSL | bash -s -- -y' \
24 | && /bin/bash -c 'set -euo pipefail && curl -sSfL https://raw.githubusercontent.com/aquaproj/aqua-installer/v3.0.1/aqua-installer | bash'
25 |
26 |
27 | VOLUME [ "/var/lib/docker" ]
28 | CMD ["sleep", "infinity"]
29 | # ENTRYPOINT ["/usr/local/share/docker-init.sh"]
30 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.241.1/containers/kubernetes-helm-minikube
3 | {
4 | "name": "devcontainer",
5 | "dockerFile": "Dockerfile",
6 | "build": {
7 | "args": {
8 | "DEVCONTAINER_USER": "vscode",
9 | "GOPATH": "/home/vscode/go"
10 | }
11 | },
12 | "runArgs": [
13 | "--init",
14 | "--privileged"
15 | ],
16 | // "runArgs": [
17 | // "--cap-add=SYS_PTRACE",
18 | // "--security-opt",
19 | // "seccomp=unconfined",
20 | // "--privileged",
21 | // "--init"
22 | // ],
23 | "mounts": [
24 | "source=minikube-config,target=/home/vscode/.minikube,type=volume",
25 | "source=${localEnv:HOME}${localEnv:USERPROFILE}/.kube,target=/home/vscode/.kube/,type=bind,consistency=cached", // support for SSH keys
26 | "source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/vscode/.ssh/,type=bind,consistency=cached", // support for SSH keys
27 | "source=${localEnv:HOME}${localEnv:USERPROFILE}/.envrc,target=/home/vscode/.envrc,type=bind,consistency=cached", // envrc from home to allow direnv to mount credentials
28 | "source=${localEnv:HOME}${localEnv:USERPROFILE}/.thy,target=/home/vscode/.thy/,type=bind,consistency=cached", // support for dsv-cli filestore based store
29 | "source=${localEnv:HOME}${localEnv:USERPROFILE}/.dsv.yml,target=/home/vscode/.dsv.yml/,type=bind,consistency=cached", // mounting for dsv-config
30 | // cache gopath directory
31 | "source=go-path,target=/home/vscode/go/,type=volume"
32 | ],
33 | "overrideCommand": false,
34 | // Configure tool-specific properties.
35 | "customizations": {
36 | // Configure properties specific to VS Code.
37 | "vscode": {
38 | // Add the IDs of extensions you want installed when the container is created.
39 | "extensions": [
40 | "trunk.io",
41 | "GitHub.vscode-pull-request-github",
42 | "yzhang.markdown-all-in-one",
43 | "sheldon-hull.extension-pack-go",
44 | "ms-azuretools.vscode-docker",
45 | "ms-kubernetes-tools.vscode-kubernetes-tools"
46 | ]
47 | }
48 | },
49 | "settings": {
50 | "terminal.integrated.profiles.linux": {
51 | "zsh-login": {
52 | "args": [
53 | "-l"
54 | ],
55 | "icon": "terminal-bash",
56 | "path": "zsh"
57 | }
58 | },
59 | "terminal.integrated.defaultProfile.linux": "zsh-login"
60 | },
61 | // Use 'forwardPorts' to make a list of ports inside the container available locally.
62 | // "forwardPorts": [],
63 | // Use 'postCreateCommand' to run commands after the container is created.
64 | // "postCreateCommand": "",
65 | // Use 'postStartCommand' to run commands after the container is created like starting minikube.
66 | "postStartCommand": "sudo chown -R vscode /home/vscode/go/ && export GOPATH=/home/vscode/go/ && echo '🔨 aqua tooling download' && aqua install && echo '✅ aqua install complete' && echo
67 | '🔨 running go mod download' && /home/vscode/.local/share/aquaproj-aqua/bin/go mod download && echo '✅ go mod download finished' && echo '🔨 downloading build tooling dependencies' &&
68 | /home/vscode/.local/share/aquaproj-aqua/bin/mage -compile ./magec && echo '✅ build tooling dependencies complete'",
69 | // Minikube does not like running as root, so use a non-root user.
70 | "remoteUser": "vscode",
71 | "containerEnv": {
72 | "ENABLE_NONROOT_DOCKER": "true",
73 | "GITHUB_OATH_TOKEN": "${localEnv:GITHUB_OATH_TOKEN}",
74 | "CGO_ENABLED": "false"
75 | },
76 | "remoteEnv": {
77 | "ENABLE_NONROOT_DOCKER": "true"
78 | },
79 | "initializeCommand": [
80 | ".devcontainer/init"
81 | ],
82 | "forwardPorts": [
83 | 10350,
84 | 2222
85 | ],
86 | "portsAttributes": {
87 | "10350": {
88 | "label": "tilt",
89 | "onAutoForward": "openBrowserOnce",
90 | "protocol": "http",
91 | "requireLocalPort": false
92 | },
93 | "2222": {
94 | "label": "remote-ssh-support",
95 | "onAutoForward": "silent"
96 | }
97 | },
98 | "hostRequirements": {
99 | "cpus": 8, // running local kind cluster and toolchain tends to run into issues with 4, let's recommend 8 (though this requires an org membership by default). Local devcontainers should be fine.
100 | "memory": "8gb",
101 | "storage": "32gb"
102 | },
103 | "features": {
104 | "ghcr.io/devcontainers/features/common-utils:1": {
105 | "version": "latest",
106 | "username": "vscode",
107 | "installOhMyZsh": true
108 | },
109 | "ghcr.io/devcontainers/features/docker-in-docker:2": {
110 | "version": "latest",
111 | "dockerDashComposeVersion": "v2",
112 | "username": "vscode",
113 | "enableNonRootDocker": "false",
114 | "moby": "true"
115 | },
116 | "ghcr.io/devcontainers/features/sshd:1": {
117 | "version": "latest"
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/.devcontainer/files/.zshrc:
--------------------------------------------------------------------------------
1 | #eval "$(direnv hook zsh)"
2 | export PATH="${AQUA_ROOT_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/aquaproj-aqua}/bin:$PATH"
3 | export PATH="$(go env GOPATH)/bin:${PATH}"
4 | export ZSH="$HOME/.oh-my-zsh"
5 | ZSH_THEME=avit
6 | plugins=(z direnv zsh-interactive-cd docker golang gh zsh-navigation-tools)
7 | source "$ZSH/oh-my-zsh.sh"
8 |
9 | if ! command -v direnv &>/dev/null; then
10 | echo "running aqua install since missing some tools like direnv"
11 | aqua install
12 | fi
13 |
14 | # Display optional first run image specific notice if configured and terminal is interactive
15 | # if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "vscodes" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then
16 | if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "vscodes" ]]; then
17 | if [ -f "$HOME/first-run-notice.txt" ]; then
18 | if command -v glow &>/dev/null; then
19 | glow "$HOME/first-run-notice.txt"
20 | else
21 | cat "$HOME/first-run-notice.txt"
22 | fi
23 | fi
24 | mkdir -p "$HOME/.config/vscode-dev-containers" || echo 'not able to create "$HOME/.config/vscode-dev-containers"'
25 | # Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it
26 | ((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &)
27 | fi
28 |
--------------------------------------------------------------------------------
/.devcontainer/files/first-run-notice.txt:
--------------------------------------------------------------------------------
1 | # Welcome to this devcontainer
2 |
3 | > This bakes in Go, Kind, Docker, and more into a self-contained dev environment.
4 |
5 | > TIP: run `glow README.md` to get a nice formatted setup guide in your terminal.
6 |
7 | Common Starting Tasks:
8 |
9 | - `glow README.md`
10 | - `mage -l`
11 | - `mage -h init`
12 | - `mage job:setup`
13 |
14 | > WARNING: You'll want to make sure to run: `direnv allow` if you haven't to load all the correct environment variables.
15 |
--------------------------------------------------------------------------------
/.devcontainer/init:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # This runs on the the host context
3 | touch "$HOME/.envrc" && echo "✅ $HOME/.envrc initialized"
4 | mkdir "$HOME/.ssh" || echo "✅ .ssh dir already exists"
5 | mkdir "$HOME/.kube" || echo "✅ .kube dir already exists"
6 | echo '✅ prep.sh setup complete'
7 |
--------------------------------------------------------------------------------
/.devcontainer/init.bat:
--------------------------------------------------------------------------------
1 | powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "New-Item (Join-Path $ENV:USERPROFILE '.ssh') -ItemType Directory -EA 0; New-Item (Join-Path $ENV:USERPROFILE '.envrc') -ItemType File -EA 0; New-Item (Join-Path $ENV:USERPROFILE '.kube') -ItemType Directory -EA 0;"
2 | echo '✅ prep setup complete'
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | # Use 4 spaces for the Python files
13 | [*.py]
14 | indent_size = 4
15 | max_line_length = 80
16 |
17 | # The JSON files contain newlines inconsistently
18 | [*.json]
19 | insert_final_newline = ignore
20 |
21 | # Minified JavaScript files shouldn't be changed
22 | [**.min.js]
23 | indent_style = ignore
24 | insert_final_newline = ignore
25 |
26 | # Makefiles always use tabs for indentation
27 | [{Makefile, makefile, GNUmakefile, Makefile.*}]
28 | indent_style = tab
29 |
30 | # Batch files use tabs for indentation
31 | [*.bat]
32 | indent_style = tab
33 |
34 | [*.md]
35 | trim_trailing_whitespace = true
36 |
37 | [*.sh]
38 | indent_style = space
39 | indent_size = 4
40 |
41 | [*.{tf,tfvars,tpl}]
42 | indent_size = 2
43 | indent_style = space
44 |
45 | [*.{go,mod,sum}]
46 | indent_style = tab
47 | indent_size = 4
48 |
--------------------------------------------------------------------------------
/.envrc:
--------------------------------------------------------------------------------
1 | # export PATH="${AQUA_ROOT_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/aquaproj-aqua}/bin:$PATH" # for those using aqua this will ensure it's in the path with all tools if loading from home
2 | export DIRENV_WARN_TIMEOUT='10s'
3 | export DIRENV_LOG_FORMAT=""
4 |
5 | INFO_COLOR="\033[1;30;40m"
6 | RESET_COLOR="\033[0m"
7 | WARNING_COLOR="\033[33m"
8 | END_WARNING_COLOR="\033[0m"
9 | IMPORTANT_COLOR="\033[104;30m"
10 | WORKING_COLOR="\033[94m"
11 | BACKGROUND_GREEN="\033[94m"
12 | RESET_BACKGROUND="\033[0;49m"
13 |
14 | # variable for setting terminal output with blue background with black text
15 | BACKGROUND_BLUE="\033[44;30m"
16 |
17 | # variable for setting terminal output with light green background with black text and bold
18 | BACKGROUND_LIGHT_GREEN="\033[1;102;30m"
19 |
20 | # variable for setting terminal output with light yellow background and black text that is bold
21 | BACKGROUND_LIGHT_YELLOW="\033[1;103;30m"
22 |
23 | source_env "$HOME"
24 | source_env_if_exists ./env/.envrc
25 | export PATH="${GOPATH}/bin:${PATH}"
26 |
27 | # This is set for local kind/minikube config to avoid touching the main kubeconfig
28 | # Loaded by direnv, this should be pulled automatically by Mage tasks, if direnv is correctly setup.
29 | export KUBECONFIG=.cache/config
30 |
31 | # Default Testing configuration for local dev work
32 | export DSV_CREDENTIALS_ANNOTATION_VALUE='app1'
33 | export DSV_K8S_TEST_SECRET_PATH='secrets:ci:tests:dsv-k8s:sync-test'
34 | # Without this codespaces might have an issues with loading with mage initially without gcc being installed
35 | export CGO_ENABLED=0
36 | export MAGEFILE_HASHFAST=1 # use mage -f to force recompile, this should make it faster if you aren't editing magefiles often
37 | export GOTEST_DISABLE_RACE=1 # this requires CGO and not sure this app is compatible with race conditions checks, run this seperately manually if needed
38 |
39 | # for tilt lsp
40 | alias tilt="$(aqua which tilt)"
41 | # easier for new folks to filter this way
42 | alias mages="$(aqua which mage-select)"
43 |
44 | eval $(minikube docker-env)
45 |
46 | if [[ -f ".env" ]]; then
47 | dotenv_if_exists ".env"
48 | else
49 | printf "${BACKGROUND_LIGHT_YELLOW}LOCAL ENVIRONMENT CONFIGURATION${RESET_COLOR}\n"
50 | printf "${WARNING_COLOR}👉 .env not found\n"
51 | printf "${WARNING_COLOR}\tSuggested fixes:\n"
52 | printf "${WARNING_COLOR}\t\t1. create ${BACKGROUND_LIGHT_GREEN}.env${RESET_COLOR}\n"
53 | printf "${WARNING_COLOR}\t\t2. ensure ${RESET_COLOR}${BACKGROUND_LIGHT_GREEN}.env${RESET_COLOR}${WARNING_COLOR} contains the following variables: \n\n"
54 | fi
55 | # Check if DSV_PROFILE_NAME is set
56 | if [[ -z "${DSV_PROFILE_NAME}" ]]; then
57 | printf "\t\t\t- ${WARNING_COLOR}👉 DSV_PROFILE_NAME not set${RESET_COLOR}\n"
58 | else
59 | printf "✔️ ${INFO_COLOR}DSV_PROFILE_NAME set${RESET_COLOR}\n"
60 | fi
61 | # Check if DSV_TENANT_NAME is set
62 | if [[ -z "${DSV_TENANT_NAME}" ]]; then
63 | printf "\t\t\t- ${WARNING_COLOR}👉 DSV_TENANT_NAME not set${RESET_COLOR}\n"
64 | else
65 | printf "✔️ ${INFO_COLOR}DSV_TENANT_NAME set${RESET_COLOR}\n"
66 | fi
67 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=lf
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # all others
2 | * @DelineaXPM/dsv-contributors
3 |
4 | # require admin review
5 | .github @DelineaXPM/dsv-admins
6 | CODEOWNERS @DelineaXPM/dsv-admins
7 |
8 | # renovate bot and no review required
9 | aqua.yaml
10 |
11 | # no extra review required for devcontainer updates
12 | .devcontainer/
13 |
--------------------------------------------------------------------------------
/.github/auto-assign.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Schema: https://github.com/kentaro-m/auto-assign-action
3 | runOnDraft: true
4 | addReviewers: true
5 | addAssignees: author
6 | numberOfReviewers: 0
7 | reviewers:
8 | - dsv-contributors
9 | reviewGroups:
10 | useReviewGroups: false
11 | filterLabels:
12 | exclude:
13 | - wontmerge
14 | - wip
15 | - incomplete pr
16 |
--------------------------------------------------------------------------------
/.github/workflows/assign.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: assign
3 | on:
4 | pull_request_target:
5 | types: [opened, ready_for_review]
6 | env:
7 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8 | jobs:
9 | assign:
10 | uses: delineaxpm/github-workflows/.github/workflows/assign.yml@main
11 | secrets: inherit
12 |
--------------------------------------------------------------------------------
/.github/workflows/changie-trigger-release.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: changie-trigger-release
3 | on:
4 | workflow_dispatch:
5 | permissions:
6 | contents: write
7 | pull-requests: write
8 | jobs:
9 | changelog:
10 | uses: delineaxpm/github-workflows/.github/workflows/changie-trigger-release.yml@main
11 | secrets: inherit
12 | with:
13 | additional_git_adds: "'charts/*'"
14 |
--------------------------------------------------------------------------------
/.github/workflows/conventional-pr.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: conventional-commit-pr-title
3 | on:
4 | pull_request:
5 | types:
6 | - opened
7 | - edited
8 | - synchronize
9 | permissions:
10 | pull-requests: read
11 | env:
12 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13 | jobs:
14 | conventional-commit-pr-title:
15 | uses: delineaxpm/github-workflows/.github/workflows/conventional-pr.yml@main
16 | secrets: inherit
17 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: lint
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 | workflow_dispatch:
8 | workflow_call:
9 |
10 | permissions:
11 | pull-requests: write
12 | checks: write
13 | contents: read
14 | jobs:
15 | lint:
16 | uses: delineaxpm/github-workflows/.github/workflows/lint.yml@main
17 | secrets: inherit
18 |
--------------------------------------------------------------------------------
/.github/workflows/release-composite.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: release-composite
3 | on:
4 | push:
5 | branches: [main]
6 | paths: [CHANGELOG.md] # your changelog file if different
7 | workflow_dispatch:
8 |
9 | # concurrency:
10 | # group: ${{ github.workflow }}-${{ github.ref }}-${{ github.action }}
11 | # cancel-in-progress: true
12 |
13 | permissions:
14 | pull-requests: write
15 | checks: write
16 | # NOTE: individual jobs define more narrowly scoped permissions.
17 | # Release requires so must be defined here
18 | contents: write
19 |
20 | jobs:
21 | lint:
22 | uses: ./.github/workflows/lint.yml
23 | secrets: inherit
24 | test:
25 | uses: ./.github/workflows/test.yml
26 | secrets: inherit
27 | release:
28 | needs: [test]
29 | uses: ./.github/workflows/release.yml
30 | secrets: inherit
31 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: release
3 | on:
4 | # push:
5 | # tags:
6 | # - 'v*'
7 | workflow_dispatch:
8 | workflow_call:
9 | concurrency:
10 | group: ${{ github.workflow }}-${{ github.ref }}-${{ github.action }}
11 | cancel-in-progress: true
12 | jobs:
13 | goreleaser:
14 | runs-on: ubuntu-latest
15 | timeout-minutes: 15
16 | steps:
17 | - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
18 |
19 | # https://github.com/magnetikonline/action-golang-cache
20 | - name: Setup Golang with cache
21 | uses: magnetikonline/action-golang-cache@797f193169d3c8ba6f60d90f50ecdadd2583fbd8 # tag=v3
22 | with:
23 | go-version: ~1.21
24 | # with:
25 | # go-version-file: go.mod
26 |
27 | - uses: aquaproj/aqua-installer@fd2089d1f56724d6456f24d58605e6964deae124 # v2.3.2
28 | with:
29 | aqua_version: v2.28.0
30 | enable_aqua_install: true
31 | aqua_opts: '--tags release'
32 | policy_allow: true
33 | env:
34 | AQUA_LOG_LEVEL: debug
35 | AQUA_OPTS: ''
36 | - name: mage-tidy
37 | uses: magefile/mage-action@a3d5bb52942181c125118a2be4b4664c3337aef6 # v2
38 | with:
39 | version: latest
40 | args: init
41 | - name: docker-login
42 | uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2
43 | with:
44 | username: ${{ secrets.DSV_DOCKER_USERNAME }}
45 | password: ${{ secrets.DSV_DOCKER_PASSWORD }}
46 | - name: quay-login
47 | uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2
48 | with:
49 | registry: quay.io
50 | username: ${{ secrets.DOCKER_QUAY_LOGIN_NAME }}
51 | password: ${{ secrets.DOCKER_QUAY_PASSWORD }}
52 | - name: mage-release
53 | uses: magefile/mage-action@a3d5bb52942181c125118a2be4b4664c3337aef6 # v2
54 | with:
55 | version: latest
56 | args: release
57 | env:
58 | # GitHub sets this automatically
59 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60 | SLACK_CHANNEL: ${{ secrets.DSV_SLACK_CHANNEL }}
61 | SLACK_WEBHOOK: ${{ secrets.DSV_SLACK_WEBHOOK }}
62 | DOCKER_ORG: ${{ secrets.DSV_DOCKER_REGISTRY }}
63 |
64 | # - name: Run GoReleaser
65 | # uses: goreleaser/goreleaser-action@ff11ca24a9b39f2d36796d1fbd7a4e39c182630a # renovate: tag=v3.1.0
66 | # with:
67 | # version: latest
68 | # args: release --rm-dist
69 | # env:
70 | # # GitHub sets this automatically
71 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
72 | # SLACK_CHANNEL: ${{ secrets.DSV_SLACK_CHANNEL }}
73 | # SLACK_WEBHOOK: ${{ secrets.DSV_SLACK_WEBHOOK }}
74 | # DOCKER_ORG: ${{ secrets.DSV_DOCKER_REGISTRY }}
75 |
--------------------------------------------------------------------------------
/.github/workflows/scan.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: scan
3 | on:
4 | workflow_call:
5 | workflow_dispatch:
6 | schedule:
7 | - cron: '35 18 * * 0'
8 | push:
9 | branches: ['main']
10 | pull_request:
11 | # The branches below must be a subset of the branches above
12 | branches: ['main']
13 | permissions:
14 | actions: read
15 | contents: read
16 | security-events: write
17 | concurrency:
18 | group: ${{ github.workflow }}-${{ github.ref }}-${{ github.action }}
19 | cancel-in-progress: true
20 | jobs:
21 | scan:
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
25 | - uses: aquaproj/aqua-installer@fd2089d1f56724d6456f24d58605e6964deae124 # v2.3.2
26 | with:
27 | aqua_version: v2.28.0
28 | enable_aqua_install: true
29 | aqua_opts: '--tags scan'
30 | env:
31 | AQUA_LOG_LEVEL: debug
32 | AQUA_OPTS: ''
33 | - name: env-config-go
34 | run: |
35 | echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
36 | # no pinning of github managed action
37 | - name: Setup Golang caches
38 | uses: actions/cache@2f8e54208210a422b2efd51efaa6bd6d7ca8920f # v3
39 | with:
40 | path: |
41 | ${HOME}/.cache/go-build
42 | ${HOME}/go/pkg/mod
43 | key: ${{ runner.os }}-golang-${{ hashFiles('**/go.sum') }}
44 | restore-keys: |
45 | ${{ runner.os }}-golang-
46 | # This should be informational, and not block as it's experimental and no exclusion logic at this time that I've found.
47 | # https://go.dev/security/vuln/#feedback
48 | - name: govuln-scan
49 | uses: elgohr/go-vulncheck-action@04c514965656cb0768b37118284fb7c9c40477db # renovate tag=v1
50 | continue-on-error: true
51 | # - name: mage-vulcheck
52 | # run: |
53 | # export PATH="${AQUA_ROOT_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/aquaproj-aqua}/bin/aqua:${PATH}"
54 | # export PATH="$(go env GOPATH)/bin:${PATH}"
55 | # mage vulncheck
56 | codeql:
57 | name: codeql-scan
58 | runs-on: ubuntu-latest
59 | strategy:
60 | fail-fast: false
61 | matrix:
62 | language: ['go']
63 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
64 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
65 |
66 | steps:
67 | - name: Checkout repository
68 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
69 |
70 | # Initializes the CodeQL tools for scanning.
71 | - name: Initialize CodeQL
72 | uses: github/codeql-action/init@b8d3b6e8af63cde30bdc382c0bc28114f4346c88 # v2
73 | with:
74 | languages: ${{ matrix.language }}
75 | # If you wish to specify custom queries, you can do so here or in a config file.
76 | # By default, queries listed here will override any specified in a config file.
77 | # Prefix the list here with "+" to use these queries and those in the config file.
78 |
79 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
80 | # queries: security-extended,security-and-quality
81 |
82 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
83 | # If this step fails, then you should remove it and run the build manually (see below)
84 | - name: Autobuild
85 | uses: github/codeql-action/autobuild@b8d3b6e8af63cde30bdc382c0bc28114f4346c88 # v2
86 |
87 | # ℹ️ Command-line programs to run using the OS shell.
88 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
89 |
90 | # If the Autobuild fails above, remove it and uncomment the following three lines.
91 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
92 | # - run: |
93 | # echo "Run, Build Application using script"
94 | # ./location_of_script_within_repo/buildscript.sh
95 |
96 | - name: Perform CodeQL Analysis
97 | uses: github/codeql-action/analyze@b8d3b6e8af63cde30bdc382c0bc28114f4346c88 # v2
98 | with:
99 | category: '/language:${{matrix.language}}'
100 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | name: stale
3 | on:
4 | schedule:
5 | - cron: 30 1 * * *
6 | workflow_dispatch:
7 |
8 | permissions:
9 | issues: write
10 | pull-requests: write
11 |
12 | jobs:
13 | stale:
14 | uses: delineaxpm/github-workflows/.github/workflows/stale.yml@main
15 | secrets: inherit
16 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: test
3 |
4 | # secrets aren't inherited to tasks, so not able to use the reusable as of 2023-02.
5 | # Using workflow directly and will revisit in the future.
6 | # uses: delineaxpm/github-workflows/.github/workflows/test.yml@main
7 | # secrets: inherit
8 | env:
9 | DSV_K8S_TEST_CONFIG: ${{ secrets.DSV_TMG_CONFIG }}
10 | DSV_K8S_TEST_SECRET_PATH: ci:tests:dsv-k8s:sync-test
11 |
12 | on:
13 | pull_request:
14 | push:
15 | tags:
16 | - v*
17 | workflow_dispatch:
18 | inputs:
19 | gotestflags:
20 | type: string
21 | description: 'GOTEST_FLAGS to pass'
22 | required: false
23 | default: '--tags=integration'
24 | workflow_call:
25 | inputs:
26 | gotestflags:
27 | type: string
28 | description: 'GOTEST_FLAGS to pass'
29 | required: false
30 | default: '--tags=integration'
31 | defaults:
32 | run:
33 | shell: bash
34 |
35 | permissions:
36 | contents: read
37 | # concurrency:
38 | # group: ${{ github.workflow }}-${{ github.ref }}-${{ github.action }}
39 | # cancel-in-progress: true
40 |
41 | jobs:
42 | test:
43 | runs-on: ubuntu-latest
44 | timeout-minutes: 5
45 | steps:
46 | - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
47 | - uses: aquaproj/aqua-installer@fd2089d1f56724d6456f24d58605e6964deae124 # v2.3.2
48 | with:
49 | aqua_version: v2.28.0
50 | enable_aqua_install: true
51 | aqua_opts: '--tags test'
52 | env:
53 | AQUA_LOG_LEVEL: debug
54 | AQUA_OPTS: ''
55 | - name: env-config-go
56 | run: |
57 | echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
58 | # no pinning of github managed action
59 | - name: Setup Golang caches
60 | uses: actions/cache@2f8e54208210a422b2efd51efaa6bd6d7ca8920f # v3
61 | with:
62 | path: |
63 | ${HOME}/.cache/go-build
64 | ${HOME}/go/pkg/mod
65 | key: ${{ runner.os }}-golang-${{ hashFiles('**/go.sum') }}
66 | restore-keys: |
67 | ${{ runner.os }}-golang-
68 | # - name: mage-init
69 | # run: |
70 | # export PATH="${AQUA_ROOT_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/aquaproj-aqua}/bin/aqua:${PATH}"
71 | # export PATH="$(go env GOPATH)/bin:${PATH}"
72 | # mage init
73 | - name: mage-testsum
74 | run: |
75 | export PATH="${AQUA_ROOT_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/aquaproj-aqua}/bin/aqua:${PATH}"
76 | export PATH="$(go env GOPATH)/bin:${PATH}"
77 | USER_GOTESTFLAGS="${{ github.event.inputs.name }}"
78 | # Use user input or fall back to --tags=integration if nothing provided
79 | GOTEST_FLAGS=${USER_GOTESTFLAGS:-"--tags=integration"}
80 | mage go:testsum ./...
81 | env:
82 | # Race conditions will be hit due to the cli driven tasks and binaries being called.
83 | GOTEST_DISABLE_RACE: 1
84 | # GOTEST_FLAGS: '${{ inputs.gotestflags }}'
85 |
86 | - uses: codecov/codecov-action@ab904c41d6ece82784817410c45d8b8c02684457 # v3.1.6
87 | with:
88 | fail_ci_if_error: false
89 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io/api/go
2 | # Edit at https://www.gitignore.io/?templates=go
3 |
4 | ### Go ###
5 | # Binaries for programs and plugins
6 | *.exe
7 | *.exe~
8 | *.dll
9 | *.so
10 | *.dylib
11 |
12 | # Test binary, built with `go test -c`
13 | *.test
14 |
15 | # Output of the go coverage tool, specifically when used with LiteIDE
16 | *.out
17 |
18 | # Dependency directories (remove the comment below to include it)
19 | # vendor/
20 |
21 | ### Go Patch ###
22 | # /vendor/
23 | /Godeps/
24 |
25 | # End of https://www.gitignore.io/api/go
26 | configs/
27 | target
28 |
29 | /dsv-injector
30 | /dsv-syncer
31 |
32 | .artifacts/
33 | .cache/
34 | /aws/
35 | /awscli.sig
36 | /awscli.zip
37 | adhoc*
38 |
39 | # Artifact File
40 | mage_output_file.go
41 | minikube-linux-amd64
42 | packages-*
43 | *.DS_Store
44 | /secret-*.yaml
45 |
46 | vendor/**/*.png
47 |
48 | Tiltfile.local
49 | .env
50 |
--------------------------------------------------------------------------------
/.gitleaks.toml:
--------------------------------------------------------------------------------
1 | # Templates: https://github.com/zricethezav/gitleaks/tree/master/examples
2 | title = "gitleaks config"
3 |
4 | [[rules]]
5 | description = "AWS Access Key"
6 | regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}'''
7 | tags = ["key", "AWS"]
8 |
9 | [[rules]]
10 | description = "AWS cred file info"
11 | regex = '''(?i)(aws_access_key_id|aws_secret_access_key)(.{0,20})?=.[0-9a-zA-Z\/+]{20,40}'''
12 | tags = ["AWS"]
13 |
14 | [[rules]]
15 | description = "AWS Secret Key"
16 | regex = '''(?i)aws(.{0,20})?(?-i)['\"][0-9a-zA-Z\/+]{40}['\"]'''
17 | tags = ["key", "AWS"]
18 |
19 | [[rules]]
20 | description = "AWS MWS key"
21 | regex = '''amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'''
22 | tags = ["key", "AWS", "MWS"]
23 |
24 | [[rules]]
25 | description = "Facebook Secret Key"
26 | regex = '''(?i)(facebook|fb)(.{0,20})?(?-i)['\"][0-9a-f]{32}['\"]'''
27 | tags = ["key", "Facebook"]
28 |
29 | [[rules]]
30 | description = "Facebook Client ID"
31 | regex = '''(?i)(facebook|fb)(.{0,20})?['\"][0-9]{13,17}['\"]'''
32 | tags = ["key", "Facebook"]
33 |
34 | [[rules]]
35 | description = "Twitter Secret Key"
36 | regex = '''(?i)twitter(.{0,20})?['\"][0-9a-z]{35,44}['\"]'''
37 | tags = ["key", "Twitter"]
38 |
39 | [[rules]]
40 | description = "Twitter Client ID"
41 | regex = '''(?i)twitter(.{0,20})?['\"][0-9a-z]{18,25}['\"]'''
42 | tags = ["client", "Twitter"]
43 |
44 | [[rules]]
45 | description = "Github"
46 | regex = '''(?i)github(.{0,20})?(?-i)['\"][0-9a-zA-Z]{35,40}['\"]'''
47 | tags = ["key", "Github"]
48 |
49 | [[rules]]
50 | description = "LinkedIn Client ID"
51 | regex = '''(?i)linkedin(.{0,20})?(?-i)['\"][0-9a-z]{12}['\"]'''
52 | tags = ["client", "LinkedIn"]
53 |
54 | [[rules]]
55 | description = "LinkedIn Secret Key"
56 | regex = '''(?i)linkedin(.{0,20})?['\"][0-9a-z]{16}['\"]'''
57 | tags = ["secret", "LinkedIn"]
58 |
59 | [[rules]]
60 | description = "Slack"
61 | regex = '''xox[baprs]-([0-9a-zA-Z]{10,48})?'''
62 | tags = ["key", "Slack"]
63 |
64 | [[rules]]
65 | description = "EC"
66 | regex = '''-----BEGIN EC PRIVATE KEY-----'''
67 | tags = ["key", "EC"]
68 |
69 |
70 | [[rules]]
71 | description = "Google API key"
72 | regex = '''AIza[0-9A-Za-z\\-_]{35}'''
73 | tags = ["key", "Google"]
74 |
75 |
76 | [[rules]]
77 | description = "Heroku API key"
78 | regex = '''(?i)heroku(.{0,20})?['"][0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}['"]'''
79 | tags = ["key", "Heroku"]
80 |
81 | [[rules]]
82 | description = "MailChimp API key"
83 | regex = '''(?i)(mailchimp|mc)(.{0,20})?['"][0-9a-f]{32}-us[0-9]{1,2}['"]'''
84 | tags = ["key", "Mailchimp"]
85 |
86 | [[rules]]
87 | description = "Mailgun API key"
88 | regex = '''(?i)(mailgun|mg)(.{0,20})?['"][0-9a-z]{32}['"]'''
89 | tags = ["key", "Mailgun"]
90 |
91 | [[rules]]
92 | description = "PayPal Braintree access token"
93 | regex = '''access_token\$production\$[0-9a-z]{16}\$[0-9a-f]{32}'''
94 | tags = ["key", "Paypal"]
95 |
96 | [[rules]]
97 | description = "Picatic API key"
98 | regex = '''sk_live_[0-9a-z]{32}'''
99 | tags = ["key", "Picatic"]
100 |
101 | [[rules]]
102 | description = "Slack Webhook"
103 | regex = '''https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}'''
104 | tags = ["key", "slack"]
105 |
106 | [[rules]]
107 | description = "Stripe API key"
108 | regex = '''(?i)stripe(.{0,20})?['\"][sk|rk]_live_[0-9a-zA-Z]{24}'''
109 | tags = ["key", "Stripe"]
110 |
111 | [[rules]]
112 | description = "Square access token"
113 | regex = '''sq0atp-[0-9A-Za-z\-_]{22}'''
114 | tags = ["key", "square"]
115 |
116 | [[rules]]
117 | description = "Square OAuth secret"
118 | regex = '''sq0csp-[0-9A-Za-z\\-_]{43}'''
119 | tags = ["key", "square"]
120 |
121 | [[rules]]
122 | description = "Twilio API key"
123 | regex = '''(?i)twilio(.{0,20})?['\"][0-9a-f]{32}['\"]'''
124 | tags = ["key", "twilio"]
125 |
126 | [[rules]]
127 | description = "Env Var"
128 | regex = '''(?i)(apikey|secret|key|api|password|pass|pw|host)=[0-9a-zA-Z-_.{}]{4,120}'''
129 |
130 | [[rules]]
131 | description = "Port"
132 | regex = '''(?i)port(.{0,4})?[0-9]{1,10}'''
133 | [rules.allowlist]
134 | regexes = ['''(?i)port ''']
135 | description = "ignore export "
136 |
137 |
138 | [[rules]]
139 | description = "Email"
140 | regex = '''[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}'''
141 | tags = ["email"]
142 | [rules.allowlist]
143 | files = ['''(?i)bashrc''']
144 | regexes = ['''(semverbot@github.com)''']
145 | description = "ignore bashrc emails"
146 |
147 |
148 | [[rules]]
149 | description = "Generic Credential"
150 | regex = '''(?i)(dbpasswd|dbuser|dbname|dbhost|api_key|apikey|secret|key|api|password|user|guid|hostname|pw|auth)(.{0,20})?['|"]([0-9a-zA-Z-_\/+!{}/=]{4,120})['|"]'''
151 | tags = ["key", "API", "generic"]
152 | # ignore leaks with specific identifiers like slack and aws
153 | [rules.allowlist]
154 | description = "ignore slack, mailchimp, aws"
155 | regexes = [
156 | '''xox[baprs]-([0-9a-zA-Z]{10,48})''',
157 | '''(?i)(.{0,20})?['"][0-9a-f]{32}-us[0-9]{1,2}['"]''',
158 | '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''',
159 | ]
160 | # Generates of noise
161 | # [[rules]]
162 | # description = "High Entropy"
163 | # regex = '''[0-9a-zA-Z-_!{}/=]{4,120}'''
164 | # file = '''(?i)(dump.sql|high-entropy-misc.txt)$'''
165 | # tags = ["entropy"]
166 | # [[rules.Entropies]]
167 | # Min = "4.3"
168 | # Max = "7.0"
169 | # [rules.allowlist]
170 | # description = "ignore ssh key and pems"
171 | # files = ['''(pem|ppk|env)$''']
172 | # paths = ['''(.*)?ssh''']
173 |
174 | [[rules]]
175 | description = "Potential bash var"
176 | regex = '''(?i)(=)([0-9a-zA-Z-_!{}=]{4,120})'''
177 | tags = ["key", "bash", "API", "generic"]
178 | [[rules.Entropies]]
179 | Min = "3.5"
180 | Max = "4.5"
181 | Group = "1"
182 |
183 | [[rules]]
184 | description = "WP-Config"
185 | regex = '''define(.{0,20})?(DB_CHARSET|NONCE_SALT|LOGGED_IN_SALT|AUTH_SALT|NONCE_KEY|DB_HOST|DB_PASSWORD|AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|DB_NAME|DB_USER)(.{0,20})?['|"].{10,120}['|"]'''
186 | tags = ["key", "API", "generic"]
187 |
188 | # [[rules]]
189 | # description = "Files with keys and credentials"
190 | # files = '''(?i)(id_rsa|passwd|id_rsa.pub|pgpass|pem|key|shadow)'''
191 |
192 | # Global allowlist
193 | [allowlist]
194 | description = "Allowlisted files"
195 | files = ['''(.*?)(jpg|gif|doc|pdf|bin)$''']
196 | paths = [
197 | '''gitleaks\.toml''',
198 | '''.devcontainer/''', # setup scripts for devcontainer/codespace
199 | '''.pre-commit-config.yaml$''',
200 | '''(go.mod|go.sum)$''',
201 | ]
202 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | ---
2 | output:
3 | formats:
4 | - format: tab
5 | linters-settings:
6 | misspell:
7 | locale: US
8 |
9 | nolintlint:
10 | allow-unused: false
11 | allow-no-explanation: []
12 | require-explanation: true
13 | require-specific: true
14 | gofumpt:
15 | extra-rules: true
16 | godox:
17 | keywords:
18 | - OPTIMIZE
19 | - HACK
20 | - TODO
21 | - BUG
22 | - FIXME
23 | godot:
24 | scope: all
25 | exclude:
26 | - //nolint
27 | - (API)
28 | - ^[ ]*@
29 | capital: true
30 | depguard:
31 | rules:
32 | main:
33 | deny:
34 | - pkg: 'github.com/sirupsen/logrus'
35 | desc: use zerolog
36 | - pkg: log
37 | desc: use zerolog
38 | - pkg: 'github.com/pkg/errors'
39 | desc: Should be replaced by standard lib errors package
40 |
41 | # gomodguard:
42 | # blocked:
43 | # modules:
44 | # - github.com/sirupsen/logrus:
45 | # recommendations:
46 | # - internal/logging
47 | # reason: logging is allowed only by zerolog. Please use zerolog
48 | # local_replace_directives: false
49 | tagliatelle:
50 | case:
51 | use-field-name: true
52 | rules:
53 | json: snake
54 | yaml: kebab
55 | xml: camel
56 | bson: camel
57 | avro: snake
58 | mapstructure: kebab
59 | errcheck:
60 | check-type-assertions: true
61 | check-blank: false
62 | exclude-functions:
63 | - io/ioutil.ReadFile
64 | - io.Copy(*bytes.Buffer)
65 | - io.Copy(os.Stdout)
66 | - io.Closer.Close
67 | - io.Closer.Body.Close
68 | govet:
69 | enable-all: true
70 | disable:
71 | - fieldalignment
72 | settings:
73 | printf:
74 | funcs:
75 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
76 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
77 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
78 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
79 | varnamelen:
80 | max-distance: 15
81 | min-name-length: 3
82 | check-receiver: false
83 | check-return: false
84 | ignore-type-assert-ok: true
85 | ignore-map-index-ok: true
86 | ignore-chan-recv-ok: true
87 | ignore-names:
88 | - err
89 | - tt
90 | - i
91 | - x
92 | - id
93 | - b
94 | - ok
95 | - zl
96 | - fs
97 |
98 | revive:
99 | ignore-generated-header: true
100 | enable-all-rules: true
101 | rules:
102 | - name: var-naming
103 | severity: error
104 | - name: line-length-limit
105 | severity: warning
106 | arguments:
107 | - 400
108 | - name: function-length
109 | severity: warning
110 | arguments: [20, 5000]
111 |
112 | linters:
113 | enable-all: true
114 | disable:
115 | - scopelint
116 | - paralleltest
117 | - noctx
118 | - wsl
119 | - lll
120 | - interfacer
121 | - golint
122 | - maligned
123 | - goimports
124 | - gci
125 | - gofmt
126 | - nlreturn
127 | - gofumpt
128 | - exhaustivestruct
129 | - exhaustruct
130 | - wrapcheck
131 | - godox
132 | - execinquery
133 | - nonamedreturns
134 | - forbidigo
135 | - structcheck
136 | - varcheck
137 | - deadcode
138 | - ifshort
139 | - godox
140 | - godot
141 | - nosnakecase
142 | - rowserrcheck # disabled due to generics, can enable in future if needed
143 | - sqlclosecheck # disabled due to generics, can enable in future if needed
144 | - wastedassign # disabled due to generics, can enable in future if needed
145 | - funlen #OVERRIDE: ok using for bot, lots of quick long commands i worked on
146 | - cyclop #OVERRIDE: ok using for bot, lots of quick long commands i worked on
147 | - gocognit #OVERRIDE: ok using for bot, lots of quick long commands i worked on
148 | - perfsprint
149 | run:
150 | timeout: 5m
151 | build-tags:
152 | - mage
153 | - tools
154 | - integration
155 | - codeanalysis
156 | issues:
157 | exclude-rules:
158 | - path: _test\.go
159 | linters:
160 | - goerr113
161 | - wrapcheck
162 | - funlen
163 | - cyclop
164 | - gocognit
165 | - unparam
166 | - varnamelen
167 | - revive
168 | - linters:
169 | - goerr113
170 | text: do not define dynamic errors
171 | - path: magefiles
172 | linters:
173 | - goerr113
174 | - wrapcheck
175 | - funlen
176 | - gocyclo
177 | - cyclop
178 | - gocognit
179 | - maintidx
180 | - deadcode
181 | - gochecknoglobals
182 | - path: magefile.go
183 | linters:
184 | - goerr113
185 | - wrapcheck
186 | - funlen
187 | - gocyclo
188 | - cyclop
189 | - gocognit
190 | - maintidx
191 | - deadcode
192 | - gochecknoglobals
193 | - linters:
194 | - goerr113
195 | text: magefiles don't need to worry about wrapping in the same way
196 | - linters:
197 | - govet
198 | - revive
199 | text: 'shadow: declaration of .err. shadows declaration'
200 | - path: mocks
201 | linters:
202 | - godot
203 | text: mocked files do not need to be checked
204 | whole-files: false
205 | exclude-dirs:
206 | - build
207 | - .artifacts
208 | - .cache
209 | - artifacts
210 | - .trunk
211 | - _tools
212 | - vendor
213 | - vendor$
214 |
--------------------------------------------------------------------------------
/.goreleaser.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 | project_name: dsv-k8s
4 | dist: .artifacts/goreleaser
5 | env:
6 | - GITHUB_TOKEN=''
7 | - GITLAB_TOKEN=''
8 | - GITEA_TOKEN=''
9 | - LOCAL_DEBUGGING=false # set to make this quick and bypass extra effort builds like archiving zip
10 | - CGO_ENABLED=0
11 | - BUILD_NAME='{{ if index .Env "BUILD_NAME" }}{{ .Env.BUILD_NAME }}{{else}}""{{end}}'
12 | before:
13 | hooks:
14 | - go mod download
15 |
16 | builds:
17 | - id: dsv-injector
18 | binary: dsv-injector
19 | main: ./cmd/injector
20 | mod_timestamp: '{{ .CommitTimestamp }}'
21 | ldflags:
22 | - -s -w
23 | - -X main.version={{ .Tag }}
24 | - -X main.commit={{ .FullCommit }}
25 | - -X main.date={{ .Now.Format "2006-01-02T15:04:05Z07:00" }} #RFC3339
26 | - -X main.builtBy=goreleaser
27 | - -X main.buildName={{ .Env.BUILD_NAME }}
28 | goos: [linux]
29 | goarch:
30 | - amd64
31 | - id: dsv-syncer
32 | binary: dsv-syncer
33 | main: ./cmd/syncer
34 | mod_timestamp: '{{ .CommitTimestamp }}'
35 | ldflags:
36 | - -s -w
37 | - -X main.version={{ .Tag }}
38 | - -X main.commit={{ .FullCommit }}
39 | - -X main.date={{ .Now.Format "2006-01-02T15:04:05Z07:00" }} #RFC3339
40 | - -X main.builtBy=goreleaser
41 | goos: [linux]
42 | goarch:
43 | - amd64
44 | archives:
45 | - id: binaries
46 | format: binary
47 |
48 | checksum:
49 | name_template: checksums.txt
50 | algorithm: sha256
51 | disable: false
52 | snapshot:
53 | name_template: '{{ incpatch .Version }}-next'
54 | changelog:
55 | disable: true
56 | sort: asc
57 | use: github
58 | groups:
59 | - title: Features
60 | regexp: "^.*feat[(\\w)]*:+.*$"
61 | order: 0
62 | - title: 'Fixes'
63 | regexp: "^.*fix[(\\w)]*:+.*$"
64 | order: 1
65 | - title: 'CI & Chore'
66 | regexp: "^.*(fix|chore|build)[(\\w)]*:+.*$"
67 | order: 2
68 | - title: Others
69 | order: 999
70 | filters:
71 | exclude:
72 | - '^docs:'
73 | - '^test:'
74 | - '^style:'
75 | dockers:
76 | - id: docker-publish
77 | goos: linux
78 | # goarch: amd64
79 | # goarm: ''
80 | # goamd64: v2
81 | image_templates:
82 | - '{{ if index .Env "DOCKER_ORG" }}{{ .Env.DOCKER_ORG }}/{{ .ProjectName }}:{{ .Tag }}{{ end }}'
83 | - '{{ if index .Env "DOCKER_ORG" }}{{ .Env.DOCKER_ORG }}/{{ .ProjectName }}:latest{{ end }}'
84 |
85 | # tag for quay publishing both with semver and latest tag
86 | - '{{ if index .Env "QUAY_ORG" }}{{ .Env.QUAY_ORG }}/{{ .ProjectName }}:{{ .Tag }}{{ end }}'
87 | - '{{ if index .Env "QUAY_ORG" }}{{ .Env.QUAY_ORG }}/{{ .ProjectName }}:latest{{ end }}'
88 |
89 | skip_push: false
90 | dockerfile: ./docker/Dockerfile.distroless
91 | use: buildx
92 | build_flag_templates:
93 | - --platform=linux/amd64
94 | - --label=org.opencontainers.image.created={{ .Now.Format "2006-01-02T15:04:05Z07:00" }}
95 | - --label=org.opencontainers.image.title={{ .ProjectName }}
96 | - --label=org.opencontainers.image.revision={{ .FullCommit }}
97 | - --label=org.opencontainers.image.version={{.Version}}
98 | # - --label=org.opencontainers.image.version="{{ .Tag }}"
99 | # local builds
100 | - id: local-docker-images
101 | goos: linux
102 | image_templates:
103 | - 'dev.local/{{ .ProjectName }}:{{ .Tag }}'
104 | - 'dev.local/{{ .ProjectName }}:latest' # This one is for dev usage so latest version, no tagged semver required in docker compose or local testing
105 | skip_push: true
106 | dockerfile: ./docker/Dockerfile.distroless
107 | use: buildx
108 | build_flag_templates:
109 | - --platform=linux/amd64
110 | - --label=org.opencontainers.image.created={{ .Now.Format "2006-01-02T15:04:05Z07:00" }}
111 | - --label=org.opencontainers.image.title={{ .ProjectName }}
112 | - --label=org.opencontainers.image.revision={{ .FullCommit }}
113 | - --label=org.opencontainers.image.version={{.Version}}
114 | announce:
115 | slack:
116 | enabled: true
117 | # The name of the channel that the user selected as a destination for webhook messages.
118 | channel: '{{ .Env.SLACK_CHANNEL }}'
119 | message_template: ':github: {{ .ProjectName }} {{ .Tag }} is out. {{ .ReleaseURL }}'
120 | # Emoji to use as the icon for this message. Overrides icon_url.
121 | icon_emoji: ':rocket:'
122 | sboms:
123 | - artifacts: binary
124 | documents:
125 | - '${artifact}.spdx.sbom'
126 |
--------------------------------------------------------------------------------
/.hadolint.yaml:
--------------------------------------------------------------------------------
1 | # Following source doesn't work in most setups
2 | ignored:
3 | - SC1090
4 | - SC1091
5 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/dsv-k8s.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/markdown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.markdownlint.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | #https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md002
3 |
4 | # enable all default tagged rules
5 | default: true
6 |
7 | # enable indentation rules by default
8 | indentation: true
9 |
10 | #MD004 - Unordered list style
11 | # Parameters: style ("consistent", "asterisk", "plus", "dash", "sublist"; default "consistent")
12 | # Defaults to dash
13 | MD004:
14 | style: dash
15 |
16 | # MD041 - First line in a file should be a top-level heading: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md041---first-line-in-a-file-should-be-a-top-level-heading
17 | MD041: false
18 | # MD007 - Unordered list indentation: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md007---unordered-list-indentation
19 | # This rule is triggered when list items are not indented by the configured number of spaces (default: 2).
20 | MD007: true
21 | no-hard-tabs: true
22 |
23 | # enable all whitespace rules, such as:
24 | # - eliminate trailing whitespace
25 | # - no tabs, use only spaces
26 | # - remove double spaces
27 | # - clean spacing up
28 | whitespace: true
29 |
30 | # require urls to have []() format, rather than just pasting raw links. This improves readability.
31 | no-bare-urls: true
32 |
33 | # Don't allow anonymous code blocks, make sure a language is specificed, so that formatting can be applied.
34 | fenced-code-language: true
35 | # Don't allow nested html to be directly used without exception being allowed.
36 | no-inline-html: true
37 | # MD025 - Multiple top-level headings in the same document -> https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md025---multiple-top-level-headings-in-the-same-document
38 | # if using front matter, we don't want a title property + a # Title to conflict
39 | MD025: true
40 |
41 | # MD013 - Line length
42 | # This is for maintainability and code diffs.
43 | # Try applying semantic line break concept for breaking up longer phrases
44 | # https://sembr.org/
45 | MD013: false
46 |
47 | # MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content
48 | # This tweaks to allow nested items to have duplicate headers.
49 | MD024:
50 | # Only check sibling headings
51 | siblings_only: true
52 | MD034: false
53 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | v20.15.0
2 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # Setup: pre-commit install
3 | # Upgrade: pre-commit autoupdate
4 | # Run: pre-commit run --all-files
5 | # https://pre-commit.com/hooks.html
6 | default_language_version:
7 | # force all unspecified python hooks to run python3
8 | python: python3
9 | node: 16.15.0
10 | exclude: |
11 | (?x)(
12 | ^.devcontainer/|
13 | ^.cache/|
14 | ^.artifacts/|
15 | ^vendor/|
16 | ^vendir.lock.yml$|
17 | vendor/
18 | )
19 | default_stages: [commit, push]
20 | repos:
21 | - repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt
22 | # https://github.com/jumanjihouse/pre-commit-hook-yamlfmt#override-defaults
23 | # https://yaml.readthedocs.io/en/latest/example.html
24 | rev: 0.2.2 # or specific tag
25 | hooks:
26 | - id: yamlfmt
27 | types_or: [yaml]
28 | args: [--mapping, '2', --sequence, '4', --offset, '2', --width, '999']
29 | - repo: https://github.com/Yelp/detect-secrets
30 | rev: v1.3.0
31 | hooks:
32 | - name: detect-secrets
33 | id: detect-secrets
34 | stages: [commit]
35 | args:
36 | [
37 | --disable-plugin,
38 | KeywordDetector,
39 | --exclude-files,
40 | .gitleaks.toml,
41 | --exclude-files,
42 | .trunk/trunk.yaml,
43 | ]
44 | - repo: https://github.com/adrienverge/yamllint.git
45 | rev: v1.27.1 # or higher tag
46 | hooks:
47 | - id: yamllint
48 | types_or: [yaml]
49 | args: [--format, parsable, --strict, --config-file, .yamllint.yaml]
50 | - repo: https://github.com/pre-commit/pre-commit-hooks
51 | rev: v4.3.0 # Use the ref you want to point at
52 | hooks:
53 | - id: trailing-whitespace
54 | args: [--markdown-linebreak-ext=md]
55 | - id: check-case-conflict
56 | name: Prevent case conflicts
57 | - id: detect-aws-credentials
58 | args: [--allow-missing-credentials]
59 | - id: mixed-line-ending
60 | name: Normalize line endings to lf
61 | args: [--fix=lf]
62 | - id: fix-byte-order-marker
63 | - id: check-added-large-files
64 | name: No large files, use artifacts for that
65 | - id: check-merge-conflict
66 | name: Prevent merge markers being committed
67 | - id: forbid-new-submodules
68 | name: Don't allow git submodules
69 | pass_filenames: false
70 | - id: no-commit-to-branch
71 | name: Don't commit to main
72 | args: [--branch, master, --branch, main]
73 | pass_filenames: false
74 | - repo: https://gitlab.com/bmares/check-json5
75 | rev: v1.0.0
76 | hooks:
77 | - id:
78 | check-json5
79 | # stages: ['commit']
80 | - repo: local
81 | hooks:
82 | - id: golines
83 | name: go-fmt
84 | description: Run formatter against changed files
85 | entry: golines --base-formatter="gofumpt" -w --max-len=120 --no-reformat-tags
86 | types: [go]
87 | language: system
88 | pass_filenames: true
89 | - id: golangci-lint
90 | name: golangci-lint
91 | description: Fast linters runner for Go.
92 | entry: golangci-lint run --fix --timeout 15s --new-from-rev=HEAD~
93 | types: [go]
94 | language: system
95 | pass_filenames: false
96 | - id: go-test-all
97 | name: go-test-all
98 | description: Run integration tests for go
99 | entry: gotestsum --format pkgname -- -shuffle=on -race -tags integration ./...
100 | stages: [commit]
101 | types: [go]
102 | language: system
103 | pass_filenames: false
104 | verbose: true
105 | - id: go-mod-tidy
106 | name: go-mod-tidy
107 | description: Run go mod tidy
108 | entry: go mod tidy
109 | stages: [commit]
110 | types: [go]
111 | language: golang
112 | pass_filenames: false
113 | verbose: true
114 | # - id: go-mod-vendor
115 | # name: go-mod-vendor
116 | # description: Run go mod vendor
117 | # # entry: #env GOTEST_FLAGS='-tags integration' mage -v go:test
118 | # entry: mod vendor
119 | # stages: [commit]
120 | # types: [go]
121 | # language: golang
122 | # pass_filenames: false
123 | # verbose: true
124 | # TODO: not certain why, but go work sync or go version etc doesn't work here
125 |
126 | - repo: https://github.com/DavidAnson/markdownlint-cli2
127 | rev: v0.5.1
128 | hooks:
129 | - id: markdownlint-cli2
130 | - repo: https://github.com/zricethezav/gitleaks
131 | rev: v8.11.0
132 | hooks:
133 | - id: gitleaks
134 | name: gitleaks-scan
135 |
--------------------------------------------------------------------------------
/.prettierrc.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | singleQuote: true
3 |
--------------------------------------------------------------------------------
/.shellcheckrc:
--------------------------------------------------------------------------------
1 | enable=all
2 | source-path=SCRIPTDIR
3 | disable=SC2154
4 |
5 | # If you're having issues with shellcheck following source, disable the errors via:
6 | # disable=SC1090
7 | # disable=SC1091
8 |
--------------------------------------------------------------------------------
/.snyk:
--------------------------------------------------------------------------------
1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
2 | version: v1.25.0
3 | ignore: {}
4 | patch: {}
5 | exclude:
6 | global:
7 | - vendor/
8 | - .devcontainer/
9 |
--------------------------------------------------------------------------------
/.trunk/.gitignore:
--------------------------------------------------------------------------------
1 | *out
2 | *logs
3 | *actions
4 | *notifications
5 | *tools
6 | plugins
7 | user_trunk.yaml
8 | user.yaml
9 | tmp
10 |
--------------------------------------------------------------------------------
/.trunk/trunk.yaml:
--------------------------------------------------------------------------------
1 | version: 0.1
2 | plugins:
3 | sources:
4 | - id: trunk
5 | ref: v1.5.0
6 | uri: https://github.com/trunk-io/plugins
7 | actions:
8 | enabled:
9 | - helm-docs-syncer
10 | - helm-docs-injector
11 | - trunk-announce
12 | - trunk-cache-prune
13 | - trunk-upgrade-available
14 | - trunk-fmt-pre-commit
15 | - trunk-check-pre-push
16 | - helm-lint
17 | # - gotestsum
18 | # - go-mod-vendor
19 | definitions:
20 | - id: gotestsum
21 | runtime: go
22 | description: run go tests on pre-push
23 | run: gotestsum --format pkgname -- -shuffle=on -tags integration ./...
24 | triggers:
25 | - git_hooks: [pre-push]
26 | - id: go-mod-vendor
27 | description: When go mod or sum is updated, go vendoring should be run to ensure it's consistent.
28 | runtime: go
29 | run: mod vendor
30 | triggers:
31 | - files: [go.mod]
32 | - id: helm-lint
33 | # runtime: go
34 | description: run helm lint on pre-push
35 | run: 'helm lint --quiet charts/*'
36 | triggers:
37 | - git_hooks: [pre-push]
38 | # AQUA installs helm-docs, so run as if already exists as these actions will be only for the refresh of charts/release process
39 | - id: helm-docs-injector
40 | description: run helm-docs on pre-commit when the helm charts are updated
41 | run: helm-docs --chart-search-root charts/dsv-injector --output-file README.md && trunk fmt
42 | triggers:
43 | - files:
44 | [
45 | 'charts/dsv-injector/values.yaml',
46 | 'charts/dsv-injector/Chart.yaml',
47 | ]
48 | - git_hooks: [pre-commit]
49 | - id: helm-docs-syncer
50 | description: run helm-docs on pre-commit when the helm charts are updated
51 | run: helm-docs --chart-search-root charts/dsv-syncer --output-file README.md && trunk fmt
52 | triggers:
53 | - files:
54 | ['charts/dsv-syncer/values.yaml', 'charts/dsv-syncer/Chart.yaml']
55 | - git_hooks: [pre-commit]
56 | runtimes:
57 | enabled:
58 | - go@1.21.0
59 | - node@18.12.1
60 | - python@3.10.8
61 | cli:
62 | version: 1.22.1
63 | lint:
64 | threshold:
65 | - linters: [gitleaks]
66 | level: high
67 | disabled:
68 | - gokart
69 | - cspell
70 | - gofmt
71 | enabled:
72 | - checkov@3.2.128
73 | - osv-scanner@1.7.4
74 | - terrascan@1.19.1
75 | - trivy@0.52.0
76 | - trufflehog@3.78.0
77 | - gofumpt@0.5.0
78 | - renovate@37.396.1
79 | - golangci-lint@SYSTEM
80 | - git-diff-check
81 | - taplo@0.8.1
82 | - markdownlint@0.41.0
83 | - prettier@3.3.1
84 | - actionlint@1.7.1
85 | - hadolint@2.12.0
86 | - gitleaks@8.18.3
87 | - shellcheck@0.10.0
88 | - shfmt@3.6.0
89 | - yamllint@1.35.1
90 | - svgo@3.3.2
91 | - prettier@2.8.3
92 | - git-diff-check
93 | - taplo@0.8.1
94 | - yamllint@1.29.0
95 | - actionlint@1.7.1
96 | - gitleaks@8.15.3
97 | - hadolint@2.12.0
98 | - markdownlint@0.41.0
99 | - shellcheck@0.10.0
100 | - shfmt@3.6.0
101 |
102 | ignore:
103 | - linters: [ALL]
104 | paths:
105 | # Generated files
106 | - .cache/*
107 | - .artifacts/*
108 | - .devcontainer/*
109 | - configs/*
110 | # Test data
111 | - b/test_data/**
112 | - vendor/*
113 | - .changes/*
114 | - 'charts/*/templates/*'
115 | # - linters: [prettier, yamllint]
116 | # paths:
117 | - linters: [checkov]
118 | paths:
119 | - '**'
120 | - '!charts/**'
121 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "[go.mod]": {
3 | "editor.formatOnSave": true
4 | },
5 | "[go]": {
6 | "debug.saveBeforeStart": "allEditorsInActiveGroup",
7 | "editor.codeActionsOnSave": {
8 | "source.fixAll": "explicit",
9 | "source.organizeImports": "never"
10 | },
11 | "editor.defaultFormatter": "go",
12 | "editor.formatOnSave": true
13 | },
14 | "[markdown]": {
15 | "editor.defaultFormatter": "trunk.io"
16 | },
17 | "[yaml]": {
18 | "editor.defaultFormatter": "redhat.vscode-yaml"
19 | },
20 | "[shell]": {
21 | "editor.defaultFormatter": "foxundermoon.shell-format"
22 | },
23 | "go.toolsManagement.autoUpdate": true,
24 | "go.useLanguageServer": true,
25 | "gopls": {
26 | "buildFlags": [
27 | "-tags=mage tools integration" // required for gopls to autocomplete mage files with mage tag
28 | ],
29 | "build.expandWorkspaceToModule": true
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "tilt-up",
8 | "type": "shell",
9 | "command": "echo \"⚙️ loading direnv\" && direnv allow .envrc && echo \"🟦 KO_DOCKER_REPO: ${KO_DOCKER_REPO}\" && echo \"⚙️ running tilt up, this may take a minute\" && tilt up",
10 | "runOptions": {
11 | "instanceLimit": 1
12 | },
13 | "promptOnClose": true,
14 | "options": {
15 | "cwd": "${workspaceFolder}",
16 | "env": {
17 | "KO_DOCKER_REPO": "ko.local"
18 | },
19 | "shell": {
20 | "executable": "zsh",
21 | "args": ["-l", "-c"]
22 | }
23 | },
24 | "isBackground": true,
25 | "group": {
26 | "kind": "build",
27 | "isDefault": true
28 | },
29 | "presentation": {
30 | "echo": true,
31 | "reveal": "always",
32 | "focus": false,
33 | "panel": "dedicated",
34 | "showReuseMessage": true,
35 | "clear": true
36 | },
37 | "icon": {
38 | "color": "terminal.ansiGreen",
39 | "id": "vm-running"
40 | }
41 | }
42 | ]
43 | }
44 |
--------------------------------------------------------------------------------
/.whitesource:
--------------------------------------------------------------------------------
1 | {
2 | "scanSettings": {
3 | "configMode": "AUTO",
4 | "configExternalURL": "",
5 | "projectToken": "",
6 | "baseBranches": [],
7 | "enableLicenseViolations": true,
8 | "displayLicenseViolations": false
9 | },
10 | "checkRunSettings": {
11 | "vulnerableCheckRunConclusionLevel": "failure",
12 | "displayMode": "diff",
13 | "useMendCheckNames": true
14 | },
15 | "issueSettings": {
16 | "minSeverityLevel": "NONE",
17 | "issueType": "DEPENDENCY"
18 | },
19 | "remediateSettings": {
20 | "enableRenovate": true,
21 | "workflowRules": {
22 | "enabled": true
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.yamllint.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | extends: default
3 | rules:
4 | line-length: disable
5 | document-start: disable # standard only requires this when directives are used, which is rarely done
6 | comments:
7 | require-starting-space: false
8 | ignore-shebangs: true
9 | min-spaces-from-content: 1
10 | comments-indentation: disable
11 |
12 | truthy:
13 | allowed-values: ['true', 'false']
14 | check-keys: false # this eliminates on: in github actions from being a failure
15 |
16 | # For all rules
17 | ignore: |
18 | .markdownlint-cli2.yaml
19 | .licenses/
20 | docs/godocs/
21 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:latest AS build
2 | RUN apk update && apk upgrade
3 | RUN apk add go
4 |
5 | WORKDIR /build
6 | COPY cmd/ ./cmd
7 | COPY internal/ ./internal
8 | COPY pkg/ ./pkg
9 | COPY go.mod go.sum ./
10 | RUN go build -o dsv-injector ./cmd/injector
11 | RUN go build -o dsv-syncer ./cmd/syncer
12 |
13 | FROM alpine:latest
14 | RUN apk update && apk upgrade
15 | RUN addgroup dsv && adduser -S -G dsv dsv
16 |
17 | COPY --from=build /build/dsv-injector /build/dsv-syncer /usr/bin/
18 |
19 | USER dsv
20 | WORKDIR /home/dsv
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2022 Delinea Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/Makefile.helpers:
--------------------------------------------------------------------------------
1 | #
2 | # Helpers - stuff that's shared between make files
3 | # Written Originally by https://github.com/cloudposse/build-harness/blob/master/Makefile.helpers, Apache License 2.0
4 | # https://github.com/cloudposse/build-harness/blob/master/LICENSE
5 | #
6 |
7 | EDITOR ?= vim
8 |
9 | SHELL = /bin/bash
10 |
11 | DEFAULT_HELP_TARGET ?= help/short
12 | HELP_FILTER ?= .*
13 |
14 | green = $(shell echo -e '\x1b[32;01m$1\x1b[0m')
15 | yellow = $(shell echo -e '\x1b[33;01m$1\x1b[0m')
16 | red = $(shell echo -e '\x1b[33;31m$1\x1b[0m')
17 |
18 | # Ensures that a variable is defined and non-empty
19 | define assert-set
20 | @$(if $($(1)),,$(error $(1) not defined in $(@)))
21 | endef
22 |
23 | # Ensures that a variable is undefined
24 | define assert-unset
25 | @$(if $($1),$(error $(1) should not be defined in $(@)),)
26 | endef
27 |
28 | warn:
29 | @printf "\e[33m🚨 make is deprecated, all automation excepting install-host for debugging have been moved to mage. Future changes should be made to mage.\e[0m\n"
30 |
31 | test/assert-set:
32 | $(call assert-set,PATH)
33 | @echo assert-set PASS
34 |
35 | test/assert-unset:
36 | $(call assert-unset,JKAHSDKJAHSDJKHASKD)
37 | @echo assert-unset PASS
38 |
39 | test/assert: test/assert-set test/assert-unset
40 | @exit 0
41 |
42 | default:: warn $(DEFAULT_HELP_TARGET)
43 | @exit 0
44 |
45 | ## Help screen
46 | help: warn
47 | @printf "Available targets:\n\n"
48 | @$(SELF) -s help/generate | grep -E "\w($(HELP_FILTER))"
49 |
50 | ## Display help for all targets
51 | help/all: warn
52 | @printf "Available targets:\n\n"
53 | @$(SELF) -s help/generate
54 |
55 | ## This help short screen
56 | help/short: warn
57 | @printf "Available targets:\n\n"
58 | @$(SELF) -s help/generate MAKEFILE_LIST="Makefile $(BUILD_HARNESS_PATH)/Makefile.helpers"
59 |
60 | # Generate help output from MAKEFILE_LIST
61 | help/generate:
62 | @awk '/^[-a-zA-Z_0-9%:\\\.\/]+:/ { \
63 | helpMessage = match(lastLine, /^## (.*)/); \
64 | if (helpMessage) { \
65 | helpCommand = $$1; \
66 | helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
67 | gsub("\\\\", "", helpCommand); \
68 | gsub(":+$$", "", helpCommand); \
69 | printf " \x1b[32;01m%-35s\x1b[0m %s\n", helpCommand, helpMessage; \
70 | } \
71 | } \
72 | { lastLine = $$0 }' $(MAKEFILE_LIST) | sort -u
73 | @printf "\n"
--------------------------------------------------------------------------------
/charts/dsv-injector/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/charts/dsv-injector/Chart.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v2
3 | name: dsv-injector
4 | description: |
5 | A Helm chart for the Delinea DevOps Secrets Vault (DSV) Injector Mutating Webhook.
6 |
7 | ```shell
8 | NAMESPACE='dsv'
9 | CREDENTIALS_JSON_FILE='.cache/credentials.json' # replace with your credentials file
10 | IMAGE_REPOSITORY='docker.io/delineaxpm/dsv-k8s'
11 | IMAGE_TAG='v1.2.4' # use latest for test, but pin to a specific version for production
12 |
13 | helm install \
14 | --namespace $NAMESPACE \
15 | --create-namespace \
16 | --set-file credentialsJson=${CREDENTIALS_JSON_FILE} \
17 | --set image.repository=${IMAGE_REPOSITORY} \
18 | --set image.tag=${IMAGE_TAG} \
19 | --atomic \
20 | --timeout "5m" \
21 | --debug -v4 \ # optional for local test iteration --values .cache/charts/dsv-injector/values.yaml \
22 | dsv-injector ./charts/dsv-injector
23 | ```
24 |
25 | An upgrade to the existing deployment can be done with:
26 |
27 | ```shell
28 | helm upgrade \
29 | --namespace $NAMESPACE \
30 | --atomic \
31 | --timeout "5m" \
32 | --debug -v4 \
33 | dsv-injector ./charts/dsv-injector
34 | ```
35 |
36 | To upgrade, ensuring that the current self signed cert that is deployed by default (if not using your own CA), run the commands below to ensure the prior hook and secret are removed so they can be recreated with the newly generated cert.
37 |
38 | ```shell
39 | kubectl --namespace $NAMESPACE delete mutatingwebhookconfiguration dsv-injector \
40 | && kubectl --namespace $NAMESPACE delete secret --timeout "5m" dsv-injector-tls \
41 | && helm upgrade \
42 | --namespace $NAMESPACE \
43 | --atomic \
44 | --timeout "5m" \
45 | --debug -v4 \
46 | dsv-injector ./charts/dsv-injector
47 | ```
48 |
49 | To uninstall the deployment, you can run:
50 |
51 | ```shell
52 | helm uninstall --namespace $NAMESPACE dsv-injector
53 | ```
54 |
55 | keywords:
56 | - Delinea
57 | - DevOps
58 | - DSV
59 | - secrets
60 | - vault
61 | type: application
62 | version: v1.2.4
63 | appVersion: latest
64 | maintainers:
65 | - name: Sheldon Hull
66 | - name: Delinea DSV Team
67 |
--------------------------------------------------------------------------------
/charts/dsv-injector/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | {{- $name := (include "dsv.dnsname" .) -}}
2 | {{- $port := int .Values.webhookPort -}}
3 | {{- $uri := trimAll "/" .Values.webhookUri -}}
4 | ✨ Deployed: {{ include "dsv.fullname" . }}
5 |
6 | 📂 Namespace: {{ .Release.Namespace }}
7 | {{ if eq .Values.service.type "ExternalName" }}
8 | 🔗 The cluster will call the webhook at {{ printf "https://%s:%d/%s" .Values.externalName $port $uri }}
9 |
10 | ❗ IMPORTANT: the endpoint certificate must have Subject Alternative Name '{{ $name }}'
11 |
12 | 🔐 The certificate chain that the cluster will use to verify the webhook is:
13 | {{- $cert := .Values.caBundle | b64dec -}}
14 | {{- $certs := split "\\n" $cert -}}
15 | {{ range $cert := $certs }}
16 | {{ $cert }}
17 | {{ end }}
18 | {{ else }}
19 | 🔗 The cluster will call the webhook at {{ printf "https://%s:%d/%s" $name $port $uri }}
20 | {{ end }}
21 |
22 | {{- if .Values.configmap }}
23 | ⚙️ ConfigMap created: {{ include "dsv.fullname" . }}-configmap
24 | {{ else }}
25 | ➖ no configmap detected, defaults used for logging level and any other configmap values
26 | {{ end }}
27 |
28 | {{- if eq .Values.service.type "ExternalName" }}
29 | ℹ️ ExternalName provided for service type, so no self signed cert will be used.
30 | {{- else -}}
31 | ➕ Will generate a self signed cert with expiration of [{{ (default 365 .Values.webhookCertExpireDays | int) }}] days.
32 | {{- end -}}
33 |
--------------------------------------------------------------------------------
/charts/dsv-injector/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/*
2 | Expand the name of the chart.
3 | */}}
4 | {{- define "dsv.name" -}}
5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
6 | {{- end }}
7 |
8 | {{/*
9 | Create a default fully qualified app name.
10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
11 | If release name contains chart name it will be used as a full name.
12 | */}}
13 | {{- define "dsv.fullname" -}}
14 | {{- if .Values.fullnameOverride }}
15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
16 | {{- else }}
17 | {{- $name := default .Chart.Name .Values.nameOverride }}
18 | {{- if contains $name .Release.Name }}
19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }}
20 | {{- else }}
21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
22 | {{- end }}
23 | {{- end }}
24 | {{- end }}
25 |
26 | {{/*
27 | Create a DNS name i.e. a fully-qualified domain name (FQDN) for the webhook.
28 | */}}
29 | {{- define "dsv.dnsname" -}}
30 | {{- print (include "dsv.name" .) "." .Release.Namespace ".svc" -}}
31 | {{- end }}
32 |
33 | {{/*
34 | Create chart name and version as used by the chart label.
35 | */}}
36 | {{- define "dsv.chart" -}}
37 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
38 | {{- end }}
39 |
40 | {{/*
41 | Common labels
42 | */}}
43 | {{- define "dsv.labels" -}}
44 | helm.sh/chart: {{ include "dsv.chart" . }}
45 | {{ include "dsv.selectorLabels" . }}
46 | {{- if .Chart.AppVersion }}
47 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
48 | {{- end }}
49 | app.kubernetes.io/managed-by: {{ .Release.Service }}
50 | dsv-filter-name: {{ .Chart.Name }}
51 | {{- end }}
52 |
53 | {{/*
54 | Selector labels
55 | */}}
56 | {{- define "dsv.selectorLabels" -}}
57 | app.kubernetes.io/name: {{ include "dsv.name" . }}
58 | app.kubernetes.io/instance: {{ .Release.Name }}
59 | dsv-filter-name: {{ .Chart.Name }}
60 | {{- end }}
61 |
--------------------------------------------------------------------------------
/charts/dsv-injector/templates/configmap.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | {{- if .Values.configmap }}
3 | apiVersion: v1
4 | kind: ConfigMap
5 | metadata:
6 | name: {{ include "dsv.fullname" . }}-configmap
7 | data:
8 | {{- toYaml .Values.configmap | nindent 2 -}}
9 | {{- end }}
--------------------------------------------------------------------------------
/charts/dsv-injector/templates/credentials-secret.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: {{ include "dsv.fullname" . }}-credentials
5 | data:
6 | config.json: {{ .Values.credentialsJson | b64enc }}
7 | type: Opaque
8 |
--------------------------------------------------------------------------------
/charts/dsv-injector/templates/deployment.yaml:
--------------------------------------------------------------------------------
1 | {{ $fullname := include "dsv.fullname" . }}
2 | {{- if ne .Values.service.type "ExternalName" -}}
3 | ---
4 | apiVersion: apps/v1
5 | kind: Deployment
6 | metadata:
7 | name: {{ .Chart.Name }}
8 | labels:
9 | {{- include "dsv.labels" . | nindent 4 }}
10 | spec:
11 | replicas: {{ .Values.replicaCount }}
12 | selector:
13 | matchLabels:
14 | {{- include "dsv.selectorLabels" . | nindent 6 }}
15 | template:
16 | metadata:
17 | {{- with .Values.podAnnotations }}
18 | annotations:
19 | checksum/last-updated: {{ now | date "2006-01-02T15:04:05Z07:00" | quote }}
20 | {{- toYaml . | nindent 8 }}
21 | {{- end }}
22 | labels:
23 | {{- include "dsv.selectorLabels" . | nindent 8 }}
24 | spec:
25 | {{- with .Values.imagePullSecrets }}
26 | imagePullSecrets:
27 | {{- toYaml . | nindent 8 }}
28 | {{- end }}
29 | containers:
30 | - name: {{ .Chart.Name }}
31 | command: [{{ .Values.image.entrypoint }}]
32 | securityContext:
33 | {{- toYaml .Values.securityContext | nindent 12 }}
34 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
35 | imagePullPolicy: {{ .Values.image.pullPolicy }}
36 | ports:
37 | - name: http
38 | containerPort: {{ .Values.containerPort }}
39 | protocol: TCP
40 | resources:
41 | {{- toYaml .Values.resources | nindent 12 }}
42 | volumeMounts:
43 | - name: cert
44 | readOnly: true
45 | mountPath: /home/nonroot/tls
46 | - name: credentials
47 | readOnly: true
48 | mountPath: /home/nonroot/credentials
49 | {{- with .Values.configmap }}
50 | envFrom:
51 | - configMapRef:
52 | name: {{ $fullname }}-configmap
53 | {{- end }}
54 | securityContext:
55 | {{- toYaml .Values.podSecurityContext | nindent 8 }}
56 | volumes:
57 | - name: credentials
58 | secret:
59 | secretName: {{ include "dsv.name" . }}-credentials
60 | - name: cert
61 | secret:
62 | secretName: {{ include "dsv.name" . }}-tls
63 | {{- end -}}
64 |
--------------------------------------------------------------------------------
/charts/dsv-injector/templates/service.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: {{ include "dsv.fullname" . }}
6 | labels:
7 | {{- include "dsv.labels" . | nindent 4 }}
8 | spec:
9 | type: {{ .Values.service.type }}
10 | {{ if eq .Values.service.type "ExternalName" }}
11 | externalName: {{ lower .Values.externalName }}
12 | {{ else }}
13 | ports:
14 | - port: {{ .Values.webhookPort }}
15 | targetPort: {{ .Values.containerPort }}
16 | selector:
17 | {{- include "dsv.selectorLabels" . | nindent 4 }}
18 | {{ end }}
19 |
--------------------------------------------------------------------------------
/charts/dsv-injector/templates/webhook.yaml:
--------------------------------------------------------------------------------
1 | {{- $tlsCert := genSelfSignedCert (include "dsv.dnsname" .) nil (list (include "dsv.dnsname" .) (include "dsv.name" .)) (default 365 .Values.webhookCertExpireDays | int) -}}
2 | {{- $existingTlsSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-tls" (include "dsv.name" .)) -}}
3 |
4 | ---
5 | apiVersion: admissionregistration.k8s.io/v1
6 | kind: MutatingWebhookConfiguration
7 | metadata:
8 | name: {{ include "dsv.fullname" . }}
9 | labels:
10 | {{- include "dsv.labels" . | nindent 4 }}
11 | annotations:
12 | checksum/last-updated: {{ now | date "2006-01-02T15:04:05Z07:00" | quote }}
13 | webhooks:
14 | - name: {{ include "dsv.fullname" . }}.{{ .Release.Namespace }}.svc
15 | failurePolicy: Fail
16 | rules:
17 | - apiGroups: [""]
18 | apiVersions: ["v1"]
19 | operations: ["CREATE"]
20 | resources: ["secrets"]
21 | scope: {{ default "*" .Values.webhookScope }}
22 | clientConfig: # Secret Reference: Not supported directly by the MutatingWebhookConfiguration API.
23 | {{- if eq .Values.service.type "ExternalName" }}
24 | caBundle: {{ .Values.caBundle }}
25 | {{ else if $existingTlsSecret }}
26 | caBundle: {{ $existingTlsSecret.data.cert }}
27 | {{- else }}
28 | caBundle: {{ $tlsCert.Cert | b64enc }}
29 | {{- end }}
30 | service:
31 | namespace: {{ .Release.Namespace }}
32 | name: {{ include "dsv.name" . }}
33 | path: {{ .Values.webhookUri }}
34 | port: {{ .Values.webhookPort }}
35 | admissionReviewVersions: ["v1"]
36 | sideEffects: {{ default "None" .Values.sideEffects }}
37 | {{- if ne .Values.service.type "ExternalName" }}
38 | ---
39 | apiVersion: v1
40 | kind: Secret
41 | metadata:
42 | name: {{ include "dsv.name" . }}-tls
43 | annotations:
44 | checksum/last-updated: {{ now | date "2006-01-02T15:04:05Z07:00" | quote }}
45 | data:
46 | {{- if $existingTlsSecret }}
47 | tls.crt: {{ $existingTlsSecret.data.cert }}
48 | tls.key: {{ $existingTlsSecret.data.key }}
49 | {{- else }}
50 | tls.crt: {{ $tlsCert.Cert | b64enc }}
51 | tls.key: {{ $tlsCert.Key | b64enc }}
52 | {{- end }}
53 | type: kubernetes.io/tls
54 | {{- end }}
55 |
--------------------------------------------------------------------------------
/charts/dsv-injector/values.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # Default values for the Delina DevOps Secrets Vault (DSV) Secrets Injector
3 | # Kubernetes API Server Mutating Webhook.
4 |
5 | # -- credentialsJson contains the JSON-formatted credentials file (see README.md)
6 | # @default - placeholder. *REQUIRED FIELD*
7 | credentialsJson: >-
8 | {
9 | "default": {
10 | "credentials": {
11 | "clientId": "",
12 | "clientSecret": ""
13 | },
14 | "tenant": "example"
15 | }
16 | }
17 |
18 | # -- replicate count
19 | # @default - 1
20 | replicaCount: 1
21 |
22 | image:
23 | repository: docker.io/delineaxpm/dsv-k8s
24 | # -- pullPolicy is the image pull policy.
25 | # If running locally built images, you'll want to set to Never to ensure local loaded images are used.
26 | # Local testing use: `Never`.
27 | # @default -- IfNotPresent
28 | pullPolicy: IfNotPresent
29 | # -- Overrides the image tag whose default is the chart appVersion.
30 | # Local Testing: Use `latest`.
31 | # @default -- the current app version/chart version
32 | tag: v1.2.4
33 | # -- Entrypoint is the path to the binary. Since the container image could contain multiple binaries, this makes sure it's correctly mapped to the binary.
34 | entrypoint: /app/dsv-injector
35 |
36 | imagePullSecrets: []
37 | nameOverride: ''
38 | fullnameOverride: ''
39 |
40 | # -- podAnnotations
41 | # @default - Includes `dsv-filter-name` for easier log selector filter.
42 | podAnnotations: {}
43 |
44 | podSecurityContext:
45 | {}
46 | # fsGroup: 2000
47 |
48 | # -- securityContext is the security context for the controller.
49 | # This uses chainguard static nonroot based image.
50 | # Reference: https://edu.chainguard.dev/chainguard/chainguard-images/reference/static/overview/
51 | securityContext:
52 | # -- readOnlyRootFilesystem is the read only root file system flag.
53 | # @default -- true
54 | readOnlyRootFilesystem: true
55 | # -- runAsNonRoot is the run as non root flag.
56 | # @default -- true
57 | runAsNonRoot: true
58 | # -- runAsUser is the run as user.
59 | # @default -- 65532 (from chainguard static image)
60 | runAsUser: 65532
61 | # -- runAsGroup is the run as group.
62 | # @default -- 65532 (from chainguard static image)
63 | runAsGroup: 65532
64 | # capabilities:
65 | # drop:
66 | # - ALL
67 | # readOnlyRootFilesystem: true
68 | # runAsNonRoot: true
69 | # runAsUser: 1000
70 |
71 | service:
72 | # -- Default port for the injector webhook service.
73 | # @default -- port 8543
74 | port: 8543
75 |
76 | # -- ClusterIP is typical when the webhook is running as a POD
77 | # However, it can also be hosted externally, which is useful for debugging, by providing the following instead:
78 | # type: ExternalName
79 | # externalName: my.fqdn
80 | # So long as:
81 | # - my.fqdn hosts an HTTPS endpoint on port {webhookPort} that answers URI {webhookUri}
82 | # - the certificate must have a Subject Alternative Name for {name}.{namespace}.{svc}, e.g., dsv-injector.dsv.svc
83 | # - the caBundle must be a base64 string containing a PEM-encoded certificate chain that validates the certifcate
84 | # caBundle: ...
85 | type: ClusterIP
86 |
87 | # -- We usually recommend not to specify default resources and to leave this as a conscious
88 | # choice for the user. This also increases chances charts run on environments with little
89 | # resources, such as Minikube. If you do want to specify resources, uncomment the following
90 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
91 | # @default -- No default values, user must specify to set resource limits.
92 | resources: {}
93 | # limits:
94 | # cpu: 100m
95 | # memory: 128Mi
96 | # requests:
97 | # cpu: 100m
98 | # memory: 128Mi
99 |
100 | # -- webhookUri is path portion of the URL of the webhook endpoint
101 | webhookUri: /inject
102 | # -- webhookPort is the port that the webhook endpoint is listening on
103 | # @default -- 8543
104 | webhookPort: 8543
105 | # -- webhookScope specifies which resources are in scope, "Cluster", "Namespaced" or "*"
106 | # @default -- "Namespaced"
107 | webhookScope: Namespaced
108 | # -- containerPort is the port that the container itself listens on
109 | containerPort: 18543
110 |
111 | # -- configmap are configuration values for the app to load.
112 | # All of these are defaulted in the template itself and only need be set if adjusting.
113 | # Since the user for the container is nonroot, only edit if you know what you are doing.
114 | # Boolean values should be passed quoted to avoid issues.
115 | # @default -- {} empty.
116 | configmap:
117 | {}
118 | # DSV_CERT:
119 | # DSV_KEY:
120 | # DSV_CREDENTIALS_JSON:
121 | # DSV_SERVER_ADDRESS:
122 | # DSV_DEBUG: 'true' # Warning: if passing boolean, use quoted string to avoid issues
123 |
124 | # -- webhookCertExpireDays specifies the number of days before the webhook certificate expires
125 | # @default -- 365
126 | webhookCertExpireDays: 365
127 |
--------------------------------------------------------------------------------
/charts/dsv-syncer/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/charts/dsv-syncer/Chart.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v2
3 | name: dsv-syncer
4 | description: |
5 | A Helm chart for the Delinea DevOps Secrets Vault (DSV) Kubernetes Synchronizer Job.
6 |
7 | ```shell
8 | NAMESPACE='dsv'
9 | IMAGE_REPOSITORY='docker.io/delineaxpm/dsv-k8s'
10 | IMAGE_TAG='v1.2.4' # use latest for test, but pin to a specific version for production
11 |
12 | helm install \
13 | --namespace $NAMESPACE \
14 | --create-namespace \
15 | --set image.repository=${IMAGE_REPOSITORY} \
16 | --set image.tag=${IMAGE_TAG} \
17 | --atomic \
18 | --timeout "5m" \
19 | --debug \ # optional --values --values .cache/charts/dsv-injector/values.yaml \
20 | dsv-syncer ./charts/dsv-syncer
21 | ```
22 | keywords:
23 | - Delinea
24 | - DevOps
25 | - DSV
26 | - secrets
27 | - vault
28 | type: application
29 | version: v1.2.4
30 | appVersion: latest
31 | maintainers:
32 | - name: Sheldon Hull
33 | - name: Delinea DSV Team
34 |
--------------------------------------------------------------------------------
/charts/dsv-syncer/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | ✨ Deployed: {{ include "dsv.fullname" . }}
2 |
3 | 📂 Namespace: {{ .Release.Namespace }}
4 |
5 | {{- if .Values.configmap }}
6 | ⚙️ ConfigMap created: {{ include "dsv.fullname" . }}-configmap
7 | {{ else }}
8 | ➖ no configmap detected, defaults used for logging level and any other configmap values
9 | {{ end }}
10 |
--------------------------------------------------------------------------------
/charts/dsv-syncer/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/*
2 | Expand the name of the chart.
3 | */}}
4 | {{- define "dsv.name" -}}
5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
6 | {{- end }}
7 |
8 | {{/*
9 | Create a default fully qualified app name.
10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
11 | If release name contains chart name it will be used as a full name.
12 | */}}
13 | {{- define "dsv.fullname" -}}
14 | {{- if .Values.fullnameOverride }}
15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
16 | {{- else }}
17 | {{- $name := default .Chart.Name .Values.nameOverride }}
18 | {{- if contains $name .Release.Name }}
19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }}
20 | {{- else }}
21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
22 | {{- end }}
23 | {{- end }}
24 | {{- end }}
25 |
26 | {{/*
27 | Create chart name and version as used by the chart label.
28 | */}}
29 | {{- define "dsv.chart" -}}
30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
31 | {{- end }}
32 |
33 | {{/*
34 | Common labels
35 | */}}
36 | {{- define "dsv.labels" -}}
37 | helm.sh/chart: {{ include "dsv.chart" . }}
38 | {{- if .Chart.AppVersion }}
39 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
40 | {{- end }}
41 | app.kubernetes.io/managed-by: {{ .Release.Service }}
42 | dsv-filter-name: {{ .Chart.Name }}
43 | {{- end }}
44 |
45 | {{/*
46 | Create the name of the service account to use
47 | */}}
48 | {{- define "dsv.serviceAccountName" -}}
49 | {{- if .Values.serviceAccount.create }}
50 | {{- default (include "dsv.fullname" .) .Values.serviceAccount.name }}
51 | {{- else }}
52 | {{- default "default" .Values.serviceAccount.name }}
53 | {{- end }}
54 | {{- end }}
55 |
56 | {{/*
57 | DSV Syncing Labels for cronjob
58 | - Required to be able to easily follow with cron job continuing to have random suffix
59 | */}}
60 | {{- define "cronjob.labels" -}}
61 | dsv-filter-name: {{ .Chart.Name }}
62 | {{- end }}
63 |
--------------------------------------------------------------------------------
/charts/dsv-syncer/templates/cluster-role-binding.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRoleBinding
4 | metadata:
5 | name: {{ include "dsv.fullname" . }}
6 | labels:
7 | {{- include "dsv.labels" . | nindent 4 }}
8 | subjects:
9 | - kind: ServiceAccount
10 | name: {{ include "dsv.serviceAccountName" . }}
11 | namespace: {{ .Release.Namespace }}
12 | roleRef:
13 | kind: ClusterRole
14 | name: {{ include "dsv.fullname" . }}
15 | apiGroup: rbac.authorization.k8s.io
16 |
--------------------------------------------------------------------------------
/charts/dsv-syncer/templates/cluster-role.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: {{ include "dsv.fullname" . }}
6 | labels:
7 | {{- include "dsv.labels" . | nindent 4 }}
8 | rules:
9 | - apiGroups: [""]
10 | resources: ["secrets"]
11 | verbs: ["list", "patch"]
12 |
--------------------------------------------------------------------------------
/charts/dsv-syncer/templates/configmap.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | {{- if .Values.configmap }}
3 | apiVersion: v1
4 | kind: ConfigMap
5 | metadata:
6 | name: {{ include "dsv.fullname" . }}-configmap
7 | data:
8 | {{- toYaml .Values.configmap | nindent 2 -}}
9 | {{- end }}
--------------------------------------------------------------------------------
/charts/dsv-syncer/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.serviceAccount.create -}}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "dsv.serviceAccountName" . }}
6 | labels:
7 | {{- include "dsv.labels" . | nindent 4 }}
8 | {{- with .Values.serviceAccount.annotations }}
9 | annotations:
10 | {{- toYaml . | nindent 4 }}
11 | {{- end }}
12 | {{- end }}
13 |
--------------------------------------------------------------------------------
/charts/dsv-syncer/templates/syncer-cronjob.yaml:
--------------------------------------------------------------------------------
1 | {{ $fullname := include "dsv.fullname" . }}
2 | {{- if .Capabilities.APIVersions.Has "batch/v1/CronJob" -}}
3 | apiVersion: batch/v1
4 | {{- else -}}
5 | apiVersion: batch/v1beta1
6 | {{- end }}
7 | kind: CronJob
8 | metadata:
9 | name: {{ .Chart.Name }}
10 | labels:
11 | {{- include "dsv.labels" . | nindent 4 }}
12 | spec:
13 | schedule: {{ quote .Values.cronJobSchedule }}
14 | jobTemplate:
15 | spec:
16 | template:
17 | metadata:
18 | labels:
19 | {{- include "cronjob.labels" . | nindent 14 }}
20 | spec:
21 | containers:
22 | - name: {{ .Chart.Name }}
23 | command: [{{ .Values.image.entrypoint }}]
24 | resources:
25 | {{- toYaml .Values.resources | nindent 14 }}
26 | securityContext:
27 | {{- toYaml .Values.securityContext | nindent 14 }}
28 | image: {{ quote (printf "%s:%s" .Values.image.repository (.Values.image.tag | default .Chart.AppVersion)) }}
29 | imagePullPolicy: {{ .Values.image.pullPolicy }}
30 | volumeMounts:
31 | - name: credentials
32 | readOnly: true
33 | mountPath: /home/nonroot/credentials
34 | {{- with .Values.configmap }}
35 | envFrom:
36 | - configMapRef:
37 | name: {{ $fullname }}-configmap
38 | {{- end }}
39 | restartPolicy: OnFailure
40 | serviceAccountName: {{ include "dsv.serviceAccountName" . }}
41 | securityContext:
42 | {{- toYaml .Values.podSecurityContext | nindent 12 }}
43 | volumes:
44 | - name: credentials
45 | secret:
46 | secretName: {{ .Values.dsvInjectorCredentialsSecretName }}
47 |
--------------------------------------------------------------------------------
/charts/dsv-syncer/values.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # Default values for the Delina DevOps Secrets Vault (DSV) Secrets Injector
3 | # Kubernetes API Server Mutating Webhook.
4 | # This is a YAML-formatted file.
5 | # Declare variables to be passed into your templates.
6 |
7 | # -- replicaCount
8 | # @default - 1
9 | replicaCount: 1
10 |
11 | image:
12 | repository: docker.io/delineaxpm/dsv-k8s
13 | # -- pullPolicy is the image pull policy.
14 | # If running locally built images, you'll want to set to Never to ensure local loaded images are used.
15 | # Local testing use: `Never`.
16 | # @default -- IfNotPresent
17 | pullPolicy: IfNotPresent
18 | # -- Overrides the image tag whose default is the chart appVersion.
19 | # Local Testing: Use `latest`.
20 | # @default -- the current app version/chart version
21 | tag: v1.2.4
22 | # -- Entrypoint is the path to the binary. Since the container image could contain multiple binaries, this makes sure it's correctly mapped to the binary.
23 | entrypoint: /app/dsv-syncer
24 | args: ['-environment', 'foo']
25 |
26 | imagePullSecrets: []
27 | nameOverride: ''
28 | fullnameOverride: ''
29 |
30 | serviceAccount:
31 | # -- Specifies whether a service account should be created
32 | # @default - true
33 | create: true
34 | # -- Annotations to add to the service account
35 | # @default - Adds `dsv-filter-name` to simplify log selector streaming
36 | annotations: {}
37 | # -- The name of the service account to use.
38 | # -- If not set and create is true, a name is generated using the fullname template
39 | name: ''
40 |
41 | # -- default annotations to add
42 | # @default - Adds `dsv-filter-name` to simplify log selector streaming
43 | podAnnotations: {}
44 |
45 | podSecurityContext:
46 | {}
47 | # fsGroup: 2000
48 |
49 | # -- securityContext is the security context for the controller.
50 | # This uses chainguard static nonroot based image.
51 | # Reference: https://edu.chainguard.dev/chainguard/chainguard-images/reference/static/overview/
52 | securityContext:
53 | # -- readOnlyRootFilesystem is the read only root file system flag.
54 | # @default -- true
55 | readOnlyRootFilesystem: true
56 | # -- runAsNonRoot is the run as non root flag.
57 | # @default -- true
58 | runAsNonRoot: true
59 | # -- runAsUser is the run as user.
60 | # @default -- 65532 (from chainguard static image)
61 | runAsUser: 65532
62 | # -- runAsGroup is the run as group.
63 | # @default -- 65532 (from chainguard static image)
64 | runAsGroup: 65532
65 | # capabilities:
66 | # drop:
67 | # - ALL
68 | # readOnlyRootFilesystem: true
69 | # runAsNonRoot: true
70 | # runAsUser: 1000
71 |
72 | # -- We usually recommend not to specify default resources and to leave this as a conscious
73 | # choice for the user. This also increases chances charts run on environments with little
74 | # resources, such as Minikube. If you do want to specify resources, uncomment the following
75 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
76 | # @default -- No default values, user must specify to set resource limits.
77 | resources:
78 | {}
79 | # limits:
80 | # cpu: 100m
81 | # memory: 128Mi
82 | # requests:
83 | # cpu: 100m
84 | # memory: 128Mi
85 |
86 | # -- dsvInjectorCredentialsSecretName is the name of thecredentialsJson secret from the dsv-injector
87 | dsvInjectorCredentialsSecretName: dsv-injector-credentials #checkov:skip=CKV_SECRET_6: this is a secret name and not an embedded secret
88 |
89 | # -- cronJobSchedule controls when the syncer runs; five asterisks means "every minute".
90 | # See [cronjob](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-schedule-syntax)
91 | # @default - every minute, ie '* * * * *'
92 | cronJobSchedule: '* * * * *'
93 |
94 | # -- configmap are configuration values for the app to load.
95 | # All of these are defaulted in the template itself and only need be set if adjusting.
96 | # Since the user for the container is nonroot, only edit if you know what you are doing.
97 | # Boolean values should be passed quoted to avoid issues.
98 | # @default -- {} empty.
99 | configmap:
100 | {}
101 | # DSV_DEBUG: true # Warning: if passing boolean, use quoted string to avoid issues
102 |
--------------------------------------------------------------------------------
/cmd/syncer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "time"
7 |
8 | "github.com/DelineaXPM/dsv-k8s/v2/internal/logger"
9 | "github.com/DelineaXPM/dsv-k8s/v2/pkg/config"
10 | "github.com/DelineaXPM/dsv-k8s/v2/pkg/syncer"
11 | "github.com/rs/zerolog"
12 |
13 | "k8s.io/client-go/rest"
14 | "k8s.io/client-go/tools/clientcmd"
15 |
16 | env "github.com/caarlos0/env/v6"
17 | )
18 |
19 | const (
20 | // ExitFailure is exit code sent for failed task.
21 | exitFailure = 1
22 | // ExitSuccess is exit code sent for running without any error.
23 | exitSuccess = 0
24 | )
25 |
26 | // main is the entrypoint for the syncer; parses the credentials file and calls syncer.Sync
27 | func main() {
28 | if err := Run(os.Args); err != nil {
29 | fmt.Fprintf(os.Stderr, "%s\n", err)
30 | os.Exit(exitFailure)
31 | }
32 | os.Exit(exitSuccess) // shouldn't hit this if run is invoked correctly
33 | }
34 |
35 | //nolint:gochecknoglobals // ok for providing as version output
36 | var (
37 | // Version is the descriptive version, normally the tag from which the app was built.
38 | // Since git tags can be changed, use Commit instead as the most accurate version.
39 | version = "dev"
40 | // Commit is the git commit hash that the build was generated from.
41 | commit = "none"
42 | // Date is the date the binary was produced.
43 | date = "unknown"
44 | // buildName is the build name for easier confirmation on local builds that a build has changed.
45 | buildName = "unknown"
46 | )
47 |
48 | // Run contains the actual invocation code for the syncer and is public to allow running integration tests with it.
49 | func Run(args []string) error { //nolint:funlen // ok for Run
50 | log := logger.New()
51 | log.Info().
52 | Str("version", version).
53 | Str("commit", commit).
54 | Str("date", date).
55 | Str("buildName", buildName).
56 | Msg("syncer version information")
57 |
58 | // Config is the configuration for the syncer.
59 | // This is provided by environment variables.
60 | type Config struct {
61 | Namespace string `env:"DSV_NAMESPACE"` // DSV_NAMESPACE is the namespace for secrets to sync. "" (the default) by default includes all namespaces.
62 | Debug bool `env:"DSV_DEBUG" envDefault:"false"` // Debug enables debug logging.
63 | KubeConfig string `env:"KUBECONFIG" envDefault:"${HOME}/.kube/config" envExpand:"true"` // KubeConfig is the path to the kubeconfig file and only required if running locally. By default the connection will be built as "incluster".
64 | CredentialsJSONFile string `env:"DSV_CREDENTIALS_JSON" envDefault:"${HOME}/credentials/config.json" envExpand:"true"` // CredentialsJSONFile is the path to the JSON formatted credentials file that is mounted as a secret.
65 | }
66 |
67 | cfg := Config{}
68 | err := env.Parse(&cfg)
69 | if err != nil {
70 | log.Error().Err(err).Msg("unable to parse environment variables")
71 | }
72 | log.Info().Strs("args", args).Msg("starting syncer, args passed, but not used, as environment variables are used instead")
73 | if cfg.Debug {
74 | zerolog.SetGlobalLevel(zerolog.DebugLevel)
75 | log.Info().Msg("debug logging enabled")
76 | }
77 |
78 | credentials, err := config.GetCredentials(cfg.CredentialsJSONFile)
79 | if err != nil {
80 | log.Fatal().Msgf("[ERROR] unable to process configuration file '%s': %s", cfg.CredentialsJSONFile, err)
81 | return fmt.Errorf("unable to process configuration file %q: %w", cfg.CredentialsJSONFile, err)
82 | }
83 | log.Info().
84 | Strs("credential_list", credentials.Names()).
85 | Int("credential_count", len(*credentials)).
86 | Msg("success loading credential sets")
87 |
88 | start := time.Now()
89 | if err := syncer.Sync(
90 | func(namespace string) (rconfig *rest.Config, err error) {
91 | rconfig, err = rest.InClusterConfig()
92 | if err != nil {
93 | log.Debug().Msg("unable to get InClusterConfig, falling back to KubeConfig")
94 |
95 | rconfig, err = clientcmd.BuildConfigFromFlags("", cfg.KubeConfig)
96 | if err != nil {
97 | log.Error().Err(err).Msg("error getting Kubernetes Client rest.Config")
98 | return nil, fmt.Errorf("error getting Kubernetes Client rest.Config: %w", err)
99 | }
100 | return rconfig, nil
101 | }
102 | return rconfig, nil
103 | },
104 | cfg.Namespace,
105 | *credentials,
106 | log,
107 | ); err != nil {
108 | log.Fatal().Msgf("[ERROR] unable to sync Secrets: %s", err)
109 | }
110 | log.Info().Dur("duration", time.Since(start)).Msg("syncer processing complete")
111 | return nil
112 | }
113 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | ---
2 | codecov:
3 | require_ci_to_pass: true
4 | comment:
5 | require_changes: true # if true: only post the comment if coverage changes
6 | coverage:
7 | status:
8 | project:
9 | default:
10 | informational: true
11 | target: auto # auto compares coverage to the previous base commit
12 | patch:
13 | default:
14 | informational: true
15 | target: auto # auto compares coverage to the previous base commit
16 | # sample regex patterns
17 | ignore:
18 | - 'magefiles'
19 | - 'examples'
20 | - '.trunk'
21 | - '.vscode'
22 | - '.devcontainer'
23 | - 'vendor'
24 |
--------------------------------------------------------------------------------
/docker/Dockerfile.chainguard:
--------------------------------------------------------------------------------
1 |
2 |
3 | # https://goreleaser.com/customization/docker/?h=scrat#how-it-works
4 | # trunk-ignore(hadolint/DL3007)
5 | FROM cgr.dev/chainguard/static:latest
6 | COPY dsv-syncer /app/dsv-syncer
7 | COPY dsv-injector /app/dsv-injector
8 |
--------------------------------------------------------------------------------
/docker/Dockerfile.distroless:
--------------------------------------------------------------------------------
1 | # Why this base image?
2 | # FROM: https://github.com/GoogleContainerTools/distroless/blob/main/base/README.md
3 | # "Distroless" images contain only your application and its runtime dependencies.
4 | # They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.
5 |
6 | # Restricting what's in your runtime container to precisely what's necessary for your app is a best practice employed by Google and other tech giants that have used containers in production for many years.
7 | # It improves the signal to noise of scanners (e.g. CVE) and reduces the burden of establishing provenance to just what you need.
8 |
9 | # Distroless images are very small. The smallest distroless image, gcr.io/distroless/static-debian11, is around 2 MiB.
10 | # That's about 50% of the size of alpine (~5 MiB), and less than 2% of the size of debian (124 MiB).
11 |
12 | # This image contains a minimal Linux, glibc-based system. It is intended for use directly by "mostly-statically compiled" languages like Go, Rust or D.
13 | # Statically compiled applications (Go) that do not require libc can use the gcr.io/distroless/static image, which contains:
14 |
15 | # ca-certificates
16 | # A /etc/passwd entry for a root user
17 | # A /tmp directory
18 | # tzdata
19 | # Most other applications (and Go apps that require libc/cgo) should start with gcr.io/distroless/base, which contains all of the packages in gcr.io/distroless/static, and
20 | # glibc
21 | # libssl
22 | # openssl
23 |
24 | # To debug: change tag to debug instead of nonroot, then
25 | # run `docker run --rm -it --entrypoint=sh dev.local/dsv-repo-template` and take a look in the image.
26 | # move back to nonroot when done.
27 | # nonroot won't work for github actions
28 | # https://docs.github.com/en/actions/creating-actions/dockerfile-support-for-github-actions#user this was for dockerfile approach, not docker image but it worked well this way.
29 |
30 |
31 | # If you change the copy location, you'll want to make sure to change the path in the helm charts and publish a new version.
32 | FROM gcr.io/distroless/static:nonroot
33 | COPY dsv-syncer /app/dsv-syncer
34 | COPY dsv-injector /app/dsv-injector
35 |
--------------------------------------------------------------------------------
/docker/Dockerfile.scratch:
--------------------------------------------------------------------------------
1 | FROM scratch
2 | ENTRYPOINT ["/dsv-repo-template"]
3 | COPY dsv-repo-template /
4 |
--------------------------------------------------------------------------------
/docs/assets/info-markup-default-creds.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/assets/random-dont-need-to-install.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/assets/warning-app1-required-for-tests.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/configure.md:
--------------------------------------------------------------------------------
1 | # Configure
2 |
3 | This focuses on the DSV configuration required to use with Kubernetes.
4 | This applies to both local testing Kubernetes and your own seperate cluster.
5 |
6 | ## Help Getting Started
7 |
8 | Run `mage dsv:setupdsv` to create the required DSV configuration for testing.
9 | This requires you to have already run `dsv init` in the project and runs against the profile you specified in `.env`.
10 | You should ensure `direnv allow` has been run and the `.env` file is loaded.
11 | Your `zsh` terminal should warn you if you didn't create the `.env` file.
12 |
13 | The order:
14 |
15 | - `mage dsv:setupdsv`
16 | - `mage dsv:createsecret`
17 | - `mage dsv:convertClientToCredentials`
18 |
19 | To tear down and recreate with new secret, just run `mage dsv:destroy`
20 |
21 | ## Manually Creating (Prior Method Before Automation)
22 |
23 | ### JSON Credentials for Helm Install
24 |
25 | The configuration requires a JSON formatted list of Client Credential and Tenant mappings.
26 |
27 | The name of the credential (such as `app1` or `default`) is used for matching the annontated credential to the right credentials file to use to connect to the connect tenant.
28 |
29 | > [!WARNING]
30 | > If you have a different top level domain, for example `eu` instead of `.com` then look at the [section on supporting alternative tld for guidance](troubleshooting.md#supporting-alternative-tld).
31 |
32 | You can place your temporary config in `.cache/credentials.json` as this is ignored by git, so that you can run the helm install command manually if you aren't doing local development.
33 |
34 |
35 |
36 | ```json
37 | {
38 | "app1": {
39 | "credentials": {
40 | "clientId": "",
41 | "clientSecret": "xxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxx-xxxxx"
42 | },
43 | "tenant": "mytenant"
44 | },
45 | "default": {
46 | "credentials": {
47 | "clientId": "",
48 | "clientSecret": "xxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxx-xxxxx"
49 | },
50 | "tenant": "mytenant"
51 | }
52 | }
53 | ```
54 |
55 | ### AZURE Entra authentication
56 |
57 | To use Azure Entra authentication add the "tenantId" and "Provider" parameters.
58 | For more information on how to set up and configure DSV for use with Azure Entra authentication
59 | [dsv-sdk-go documentation](https://github.com/DelineaXPM/dsv-sdk-go/tree/main/example/azure)
60 |
61 | ```json
62 | {
63 | "default": {
64 | "credentials": {
65 | "clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
66 | "clientSecret": "zzzz~zzzzzz.zzzzzzzzzzzzz~zzzzzzzzzzz"
67 | },
68 | "tenant": "youTenantName",
69 | "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
70 | "Provider": 3
71 | }
72 | }
73 | ```
74 |
75 | ### Update Manifests
76 |
77 | This would be referenced by a Kubernetes secret with annotations like:
78 |
79 | ```yaml
80 | ---
81 | apiVersion: v1
82 | kind: Secret
83 | metadata:
84 | name: user-domain-pass
85 | annotations:
86 | dsv.delinea.com/credentials: app1
87 | dsv.delinea.com/set-secret: 'tests:dsv-k8s'
88 | ```
89 |
90 | If using the provided examples, you can edit: `.cache/manifests` and adjust the secrets to map.
91 | You can use all of the provided manifests to test the different behavior, or just deploy one if desired.
92 |
93 | ## Configuring Credentials in Kubernetes To Talk to DSV
94 |
95 | ## Configuring DSV
96 |
97 | The following is an example of the steps to setup for testing, but can be modified to support your use case.
98 |
99 | Create the role that will allow creating a client for programmatic access
100 |
101 | ```shell
102 | dsv role create --name 'k8s' --desc 'test profile for k8s'
103 | dsv secret create --path 'tests:dsv-k8s' --data '{"password": "admin","username": "admin"}'
104 | ```
105 |
106 | Create a policy that allows the local user to read the secret, modify this to the correct user/group mapping:
107 |
108 | ```shell
109 | dsv policy create -- actions 'read' --path 'secrets:k8s' --desc 'test access to secret' --resources 'secrets:k8s:<.*>' --subjects 'roles:k8s'
110 | dsv client create --role k8s
111 | ```
112 |
--------------------------------------------------------------------------------
/docs/devcontainer.md:
--------------------------------------------------------------------------------
1 | # Devcontainer
2 |
3 | ## Codespaces
4 |
5 | Use the GitHub cli to create the codespace or do this from the browser.
6 | Ideally, use minimum of 8gb ram configuration or you'll run into issues with nested Kubernetes setup.
7 |
8 | Example invocation:
9 |
10 | ```shell
11 | gh codespace create \
12 | --display-name dsv-k8s \
13 | --machine 'standardLinux32gb' \
14 | --repo DelineaXPM/dsv-k8s \
15 | --status \
16 | --retention-period "5d"
17 | ```
18 |
19 | ## Prerequisites
20 |
21 | - Docker
22 | - Visual Studio Code
23 |
24 | ## I'm starting from scratch
25 |
26 | > **_NOTE_**
27 | > Docker is left out of these directions, just install that from [Docker Desktop](https://www.docker.com/products/docker-desktop/) site.
28 |
29 | ### Windows
30 |
31 | - [Install chocolatey (package manager for Windows)](https://chocolatey.org/install#individual) (provides single line command to run).
32 | - Run `choco install vscode -y`
33 |
34 | ### MacOS
35 |
36 | - [Homebrew](https://brew.sh/)
37 |
38 | - Run `brew install visual-studio-code`
39 |
40 | ### Linux
41 |
42 | - You'll have to install the apps manually.
43 |
44 | ### After You've Setup VSCode
45 |
46 | Run `code --install-extension ms-vscode-remote.remote-containers`
47 |
48 | - For supporting Codespaces: `code --install-extension GitHub.codespaces`
49 |
50 | ## I already use devcontainers
51 |
52 | - Ensure you've got Remote Containers or Codespace extension installed as mentioned in directions above and you'll be good to start.
53 |
54 | ## Spin It Up
55 |
56 | > **_NOTE_**
57 | >
58 | > 🐎 PERFORMANCE TIP: Using the directions provided for named container volume will optimize performance over trying to just "open in container" as there is no mounting files to your local filesystem.
59 |
60 | Use command pallet with vscode (Control+Shift+P or F1) and type to find the command `Remote Containers: Clone Repository in Named Container`.
61 |
62 | - Put the git clone url in, for example: `https://github.com/DelineaXPM/dsv-k8s.git`
63 | - Name the volume and directory both dsv-k8s or whatever you prefer.
64 |
65 | > **Note**
66 | > This is a large development image (10GB). The first time you run this it will take a while.
67 | > However, after this first run, rebuilding the container to start over should be minimal time, as you'll have the majority of Docker image cached locally.
68 |
69 | This includes (for updated info just look at dockerfile):
70 |
71 | - Embedded docker
72 | - Embedded Kind/Minikube (kubernetes)
73 | - Go
74 | - Dotnet
75 | - Python
76 | - Node
77 | - Go tools for linting, formatting, and testing.
78 | - Extensions for VSCode defined in `.devcontainers`, such as Go, Kubernetes & Docker, and some others.
79 | - Initial placeholder `.zshrc` file included to help initialize usage of `direnv` for automatically loading default `.envrc` which contains local developement default environment variables.
80 |
81 | ### After Devcontainer Loads
82 |
83 | 1. Accept "Install Recommended Extensions" from popup, to automatically get all the preset tools, such as Kubernetes, Go and others setup.
84 | 1. Open a new `zsh-login` terminal and allow the automatic setup to finish, as this will ensure all other required tools are setup.
85 | - Make sure to run `direnv allow` as it prompts you, to ensure all project and your personal environment variables (optional).
86 | 1. Make sure Go 1.19 is the correct version running with `go version`.
87 | 1. If it's not, run `sudo .devcontainer/library-scripts/go-debian.sh "1.19"`
88 | 1. Run setup task:
89 | - Using CLI: Run `mage init`
90 |
--------------------------------------------------------------------------------
/docs/developer-debugging.md:
--------------------------------------------------------------------------------
1 | # Developer Debugging
2 |
3 | This documentation comes from the original `make` driven build process.
4 | It hasn't been migrated to `mage` and will be noted here unless deprecated.
5 |
6 | ## Host (for debugging)
7 |
8 | Per above, typically, the injector runs as a POD in the cluster but running it on the host makes debugging easier.
9 |
10 | ```sh
11 | make install-host EXTERNAL_NAME=laptop.mywifi.net CA_BUNDLE=$(cat /path/to/ca.crt | base64 -w0 -)
12 | ```
13 |
14 | For it to work:
15 |
16 | - The certificate that the injector presents must validate against the `$(CA_BUNDLE)`.
17 | - The certificate must also have a Subject Alternative Name for `$(INJECTOR_NAME).$(NAMESPACE).svc`.
18 | By default that's `dsv-injector.dsv.svc`.
19 |
20 | - The `$(EXTERNAL_NAME)` is a required argument, and the name itself must be resolvable _inside_ the cluster.
21 | **localhost will not work**.
22 |
23 | If the `$(CA_BUNDLE)` is argument is omitted, `make` will attempt to extract it from `kubectl config`:
24 |
25 | ```make
26 | install-host: CA_BUNDLE_KUBE_CONFIG_INDEX = 0
27 | install-host: CA_BUNDLE_JSON_PATH = {.clusters[$(CA_BUNDLE_KUBE_CONFIG_INDEX)].cluster.certificate-authority-data}
28 | install-host: CA_BUNDLE=$(shell $(KUBECTL) config view --raw -o jsonpath='$(CA_BUNDLE_JSON_PATH)' | tr -d '"')
29 |
30 | ```
31 |
32 | which will make:
33 |
34 | ```sh
35 | kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | tr -d '"'
36 | ```
37 |
38 | Optionally set `$(CA_BUNDLE_KUBE_CONFIG_INDEX)` to use `1`, to use the second cluster in your configuration,
39 | `2` for the third and so on.
40 | ℹ️ All this assumes that the injector uses a certificate signed by the cluster CA.
41 | There are several options like [cert-manager](https://cert-manager.io/)
42 | for getting cluster-signed certs, however,
43 | this simple [bash script](https://gist.github.com/amigus/b4e6e642f88e756be1996e44a1c35349)
44 | will request and grant a suitable certificate from the cluster using cURL and OpenSSL.
45 | To use it:
46 |
47 | ```sh
48 | get_k8s_cert.sh -n dsv-injector -N dsv
49 | ```
50 |
51 | Now run it:
52 |
53 | ```sh
54 | ./dsv-injector -cert ./dsv-injector.pem -key ./dsv-injector.key -credentials ./configs/credentials.json -address :8543
55 | ```
56 |
--------------------------------------------------------------------------------
/docs/developer-reference.md:
--------------------------------------------------------------------------------
1 | # Devcontainer Based Setup
2 |
3 | - [Devcontainer Based Setup](#devcontainer-based-setup)
4 | - [Troubleshooting](#troubleshooting)
5 | - [Error With Permissions On Go Directories](#error-with-permissions-on-go-directories)
6 | - [Mismatch With Checksum for Go Modules](#mismatch-with-checksum-for-go-modules)
7 | - [Connecting to Services Outside of devcontainer](#connecting-to-services-outside-of-devcontainer)
8 |
9 | ## Troubleshooting
10 |
11 | ## Error With Permissions On Go Directories
12 |
13 | Clear the directories with `rm -rf /home/vscode/go` and then try `mage init` to redownload packages.
14 |
15 | > Known issue: Haven't figured out why this is being set incorrectly yet
16 |
17 | ### Mismatch With Checksum for Go Modules
18 |
19 | - Run `go clean -modcache && go mod tidy`.
20 |
21 | ### Connecting to Services Outside of devcontainer
22 |
23 | You are in an isolated, self-contained Docker setup.
24 | The ports internally aren't the same as externally in your host OS.
25 | If the port forward isn't discovered automatically, enable it yourself, by using the port forward tab (next to the terminal tab).
26 |
27 | 1. You should see a port forward once the services are up (next to the terminal button in the bottom pane).
28 | 1. If the click to open url doesn't work, try accessing the path manually, and ensure it is `https`.
29 | Example: `https://127.0.0.1:9999`
30 |
31 | You can choose the external port to access, or even click on it in the tab and it will open in your host for you.
32 |
--------------------------------------------------------------------------------
/docs/helm-install.md:
--------------------------------------------------------------------------------
1 | ## Helm Install
2 |
3 | Installation of charts into the a cluster requires [Helm](https://helm.sh).
4 |
5 | There are two separate charts for the `dsv-injector` and the `dsv-syncer`.
6 |
7 | - The `dsv-injector` chart imports `credentials.json` from the filesystem and stores it in a Kubernetes Secret.
8 | - The `dsv-syncer` chart refers to that Secret _instead of creating its own_.
9 |
10 | See [configure](configure.md#json-credentials-for-helm-install)
11 |
12 | ```shell
13 | NAMESPACE='testing'
14 | CREDENTIALS_JSON_FILE='.cache/credentials.json'
15 | IMAGE_REPOSITORY='docker.io/delineaxpm/dsv-k8s'
16 |
17 | helm install
18 | --namespace $NAMESPACE
19 | --create-namespace \
20 | --set-file credentialsJson=${CREDENTIALS_JSON_FILE} \
21 | --set image.repository=${IMAGE_REPOSITORY} \
22 | dsv-injector ./charts/dsv-injector
23 |
24 | helm install
25 | --namespace $NAMESPACE
26 | --create-namespace \
27 | --set-file credentialsJson=${CREDENTIALS_JSON_FILE} \
28 | --set image.repository=${IMAGE_REPOSITORY} \
29 | dsv-syncer ./charts/dsv-syncer
30 | ```
31 |
--------------------------------------------------------------------------------
/docs/local-cli-invoke.md:
--------------------------------------------------------------------------------
1 | # Local CLI Invoke
2 |
3 | The cli can be invoked locally.
4 |
5 | The injector uses the HTTPS server built-in to the Golang [http](https://pkg.go.dev/net/http)
6 | package to host the Kubernetes Mutating Webhook Webservice.
7 |
8 | ```bash
9 | $ ./dsv-injector -h
10 | Usage of ./dsv-injector:
11 | -address string
12 | the address to listen on, e.g., 'localhost:8080' or ':8443' (default ":18543")
13 | -cert string
14 | the path of the public certificate file in PEM format (default "tls/cert.pem")
15 | -credentials string
16 | the path of JSON formatted credentials file (default "credentials/config.json")
17 | -key string
18 | the path of the private key file in PEM format (default "tls/key.pem")
19 | ```
20 |
21 | Thus the injector can run "anywhere," but, typically,
22 | the injector runs as a POD in the Kubernetes cluster that uses it.
23 | The syncer is a simple Golang executable.
24 | It typically runs as a Kubernetes CronJob, but it will run outside the cluster.
25 |
26 | ```bash
27 | $ ./dsv-syncer -h
28 | Usage of ./dsv-syncer:
29 | -credentials string
30 | the path of JSON formatted credentials file (default "credentials/config.json")
31 | -kubeConfig string
32 | the Kubernetes Client API configuration file; ignored when running in-cluster (default "/home/user/.kube/config")
33 | -namespace string
34 | the Kubernetes namespace containing the Secrets to sync; "" (the default) for all namespaces
35 | ```
36 |
--------------------------------------------------------------------------------
/docs/local-kubernetes.md:
--------------------------------------------------------------------------------
1 | # Local Kubernetes
2 |
3 | For easier development workflow, the project has prebuilt tasks for both minikube and kind kubernetes tools.
4 |
5 | As of 2023-02, the default behavior is to use minikube since it handles updating the kubeconfig locally a little more consistently in the tests run.
6 |
7 | ## Working With Kubernetes & Stack Locally
8 |
9 | > **_NOTE_**
10 | > For any tasks get more help with `-h`, for example, run `mage -h k8s:init`
11 |
12 | For local development, Mage tasks have been created to automate most of the setup and usage for local testing.
13 |
14 | - Ensure your local `configs/credentials.json` exists.
15 | - run `mage job:init` to setup a local k8s cluster, initial local copies of the helm chart and kubernetes manifest files.
16 | - Modify the `.cache/dsv-injector/values.yaml` with the embedded credentials.json contents matching your `configs/credentials.json`.
17 | - Modify the `.cache/manifests/*.yaml` files to match the credentials you want to test against.
18 | - To deploy (or redeploy after changes) all the helm charts and kuberenetes manifests run `mage job:redeploy`.
19 |
20 | ## Using Minikube With VM Driver
21 |
22 |
23 | ℹ️ Using Minikube With VM Driver
24 |
25 | To deploy to Minikube set-up with the VM driver, e.g., Linux [kvm2](https://minikube.sigs.k8s.io/docs/drivers/kvm2/)
26 | or Microsoft [Hyper-V](https://minikube.sigs.k8s.io/docs/drivers/hyperv/),
27 | enable the Minikube built-in registry and use it to make the image available to the Minikube VM:
28 |
29 | ```shell
30 | minikube addons enable registry
31 | ```
32 |
33 | ❗NOTE: run Minikube [tunnel](https://minikube.sigs.k8s.io/docs/commands/tunnel/)
34 | in a separate terminal to make the registry service available to the host.
35 |
36 | ```shell
37 | minikube tunnel
38 | ```
39 |
40 | _It will run continuously, and stopping it will render the registry inaccessible._
41 |
42 | Next, get the _host:port_ of the registry:
43 |
44 | ```shell
45 | kubectl get -n kube-system service registry -o jsonpath="{.spec.clusterIP}{':'}{.spec.ports[0].port}"
46 | ```
47 |
48 | Finally, follow the [Remote Cluster](#remote-cluster)
49 | instructions using it as `$(REGISTRY)`
50 |
51 |
52 |
--------------------------------------------------------------------------------
/docs/local-testing.md:
--------------------------------------------------------------------------------
1 | # Local Testing
2 |
3 | ## First Time Setup
4 |
5 | - A valid DSV tenant.
6 | - Creation of a dsv secret and the configured client credentials to setup this.
7 | See [configuring-dsv](configure.md#configuring-dsv)
8 | - The test helm chart values file to be updated with the credentials.
9 | It's located at: `.cache/dsv-injector/values.yaml`.
10 |
11 |
12 |
13 | ## PENDING Contributor Improvements
14 |
15 | For dsv-team members, the goal is to load all this directly from a team vault. Right now this project has not been migrated to this, so you have to setup manually the first time.
16 |
17 | ## Test Environment Configuration
18 |
19 | | Environment Variable | Default | Explanation |
20 | | -------------------------------------- | -------------------------------- | ----------------------------------------------------------- |
21 | | `DSV_K8S_TEST_CONFIG` | _none_ | Contain a JSON string containing a valid `credentials.json` |
22 | | `DSV_K8S_TEST_SECRET_PATH` | `/test/secret` | The path to the secret to test against in the vault |
23 | | DEPRECATED: `DSV_K8S_TEST_CONFIG_FILE` | `../../configs/credentials.json` | The path to a valid `credentials.json` |
24 |
25 | ℹ️ NOTE: `DSV_K8S_TEST_CONFIG` takes precedence over `DSV_K8S_TEST_CONFIG_FILE`
26 |
27 | For example:
28 |
29 | ```shell
30 | DSV_K8S_TEST_CONFIG='{"app1":{"credentials":{"clientId":"","clientSecret":""},"tenant":"mytenant"}}' \
31 | DSV_K8S_TEST_SECRET_PATH=my:test:secret \
32 | mage go:testsum ./...
33 | ```
34 |
--------------------------------------------------------------------------------
/docs/release.md:
--------------------------------------------------------------------------------
1 | # Release
2 |
3 | ## Release Notes
4 |
5 | This project uses an different approach to release, driving it from changelog and versioned changelog notes instead of tagging.
6 |
7 | > Use [changie](https://changie.dev/guide/quick-start/) quick start for basic review.
8 |
9 | ### Creating New Notes
10 |
11 | - During development, new changes of note get tracked via `changie new`. This can span many pull requests, whatever makes sense as version to ship as changes to users.
12 | - To release the changes into a version, `changie batch ` (unless breaking changes occur, you'll want to stick with minor for feature additions, and patch for fixes or non app work.
13 |
14 | Keep your summary of changes that users would care about in the `.changes/` files it will create.
15 |
16 | ### Release
17 |
18 | Update [CHANGELOG.md](CHANGELOG.md) by running `changie merge` which will rebuild the changelog file with all the documented notes.
19 |
20 | ### Format & Lint
21 |
22 | - Run `trunk fmt --all; trunk check --all` to finalize run through.
23 | - Push changelog via PR or direct if you have permissions and this will trigger the [release-composite](.github/workflows/release-composite.yml). If any issues, retrigger manually via `gh workflow run release-composite`.
24 | - Release should be published in the [releases](https://github.com/DelineaXPM/dsv-repo-template/releases)
25 | - Edit the release and click "update release" to ensure it publishes to the marketplace. Unfortunately, creating a release doesn't trigger the marketplace release without doing this step. While this can be automated through other actions, I've opted due to time constraints to leave that last step as a manual one.
26 |
27 | ## FAQ
28 |
29 | ### What drives the version number for the release?
30 |
31 | Changie notes are named like `v1.0.4.md`.
32 | This version number will be used to set the version of the release, so the docs in essence will be the version source of truth.
33 |
34 | ### Conventional Commit
35 |
36 | We use [conventional commit](https://www.conventionalcommits.org/en).
37 | Pull requests must adhere to this to be merged.
38 |
39 | Description should be bullet point list or longer-form content to describe anything the title doesn't make clear.
40 |
--------------------------------------------------------------------------------
/docs/setup-developer.md:
--------------------------------------------------------------------------------
1 | # Setup Developer
2 |
3 | > Important: All the core local workflow tasks to build and deploy to minikube are wrapped up in mage tasks
4 | >
5 | > Try `mage` by itself to list.
6 | > Use `mage job:*` tasks to help simplify the process.
7 |
8 | 1. [Setup developer tooling](setup-project.md)
9 | 2. [Create DSV Credentials for Testing](configure.md)
10 | 3. [Configure The Manifests](configure.md#update-manifests)
11 | 4. Once credentials are configured in `.cache/dsv-injector/values.yaml`
12 | 1. 1st time: `mage job:init`.
13 | 2. 1st time/Anytime You updated Go code: `mage job:rebuildimages`.
14 | 3. Any time you want to redeploy the kubernetes & helm charts to minikube: `mage job:redeploy`.
15 |
16 | As always, the source of truth is `mage` so if the task names in the doc don't work, check the CLI for the proper commands.
17 |
18 | ## Optional
19 |
20 | If you are using codespaces, most of the tooling should be ready out of the box as long as you open `zsh` terminal.
21 | Run `tilt up` and then you can invoke much of this (including watch the logs stream) from the terminal.
22 |
23 | ## Reference
24 |
25 | - Optional: [devcontainer/codespaces](devcontainer.md)
26 | - Local Kubernetes Overview: [Kubernetes](local-kubernetes.md)
27 |
--------------------------------------------------------------------------------
/docs/setup-project.md:
--------------------------------------------------------------------------------
1 | # Setup Project
2 |
3 | ## Compatibility
4 |
5 | Linux & MacOS is supported out of the box for local development.
6 | Windows with WSL2 should also work fine.
7 |
8 | While the majority of this is cross-platform, the automatically linting and some other commands are only compatible with Linux/MacOS.
9 |
10 | ## Overview
11 |
12 | - Mage: Mage is a Go based automation alternative to Make and provides newer functionality for local Kind cluster setup, Go development tooling/linting, and more.
13 | Use [aqua](#aqua) to automatically install.
14 | - Run `mage` to list all available tasks, and `mage init` to setup developer tooling.
15 | Get more detail on a task, if it's available by running `mage -h init`.
16 |
17 | - Make: Makefiles provide core automation from the original project.
18 | - This has slowly been phased out for the more robust Mage tasks.
19 | Most of your usage won't touch Make.
20 | The only usage that _might_ use this is the local cert based setup for debugger.
21 | This hasn't been used in years by current maintainers, as log streaming from mage/tilt UI have been primary method.
22 | - For anything other than running the debugger, use `mage` commands which have been regularly improved and tested and move any new automation to the magefiles.
23 |
24 | ## Initial Setup
25 |
26 | ## Aqua
27 |
28 | This tool will ensure all the core development tools, including Go, are installed and setup without needing to run `apt` or other package managers.
29 |
30 | Install [aqua](https://aquaproj.github.io/docs/tutorial-basics/quick-start#install-aqua) and have it configured in your path per directions.
31 |
32 | Run `aqua install` for tooling such as changie or others for the project.
33 |
34 | Ensure your profile has this in it:
35 |
36 | ```shell
37 | export PATH="${AQUA_ROOT_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/aquaproj-aqua}/bin:$PATH" # for those using aqua this will ensure it's in the path with all tools if loading from home
38 | ```
39 |
40 | ## When Using Without Devcontainer/Codespaces
41 |
42 | - Install Aqua
43 | - Alternative: Manually ensure Go is installed.
44 | - Run `aqua policy allow` to allow the custom `go install` package to run.
45 | - Run `mage init` to install tooling.
46 | - Done automatically by Mage -> Install [trunk](https://trunk.io/products/check) (quick install script: `curl https://get.trunk.io -fsSL | bash`)
47 | - This will allow faster installs of project tooling by grabbing binaries for your platform more quickly (most of the time release binaries instead of building from source).
48 |
49 | > If you get an error with a go installation, just try once more as aqua installs in parallel and might not have finished installing Go before trying to run `go install` first.
50 |
51 | ## Direnv
52 |
53 | This loads environment variables for the project automatically.
54 |
55 | You should hook into your shell, for example with zsh: `eval "$(direnv hook zsh)"`.
56 |
57 | Other shells are supported, but this project is only tested with zsh.
58 |
59 | > [Hook Into Your Shell](https://direnv.net/docs/hook.html)
60 |
61 | Direnv: Default test values are loaded on macOS/Linux based system using [direnv](https://direnv.net/docs/installation.html).
62 |
63 | Run `direnv allow` in the directory to load default env configuration for testing.
64 |
--------------------------------------------------------------------------------
/docs/troubleshooting.md:
--------------------------------------------------------------------------------
1 | # Troubleshooting
2 |
3 | ## Supporting Alternative TLD
4 |
5 | If you are using an alternative TLD, such as `https://{mytenant}.secretsvaultcloud.eu`, try adding the tld to the credentials file.
6 |
7 | ```json
8 | {
9 | "default": {
10 | "credentials": {
11 | "clientId": "",
12 | "clientSecret": ""
13 | },
14 | "tenant": "mytenant",
15 | "tld": "eu"
16 | }
17 | }
18 | ```
19 |
20 | ## Obtaining Logs
21 |
22 | For both customers and development, stern allows easier debugging by providing a stream of the logs for both syncer & injector in one workflow.
23 |
24 | Use Stern to easily stream cross namespace logs with the `dsv-filter-selector` by running:
25 |
26 | Aqua installs this automatically, but if you want to do this manually grab from github releases like this
27 |
28 | If not using the `aqua`, you can modify the following command to match the version and OS you are using and download directly.
29 |
30 | ```shell
31 | $(curl -fSSl https://github.com/wercker/stern/releases/download/1.11.0/stern_linux_amd64 -o ./stern) && sudo chmod +x ./stern && sudo mv ./stern /usr/local/bin
32 | ```
33 |
34 | Alternative install options: [Stern Installation](https://github.com/stern/stern#installation)
35 |
36 | ### Alternative - If Using Mage For Local Development
37 |
38 | While `mage k8s:logs` will run this for you, manually you can invoke like this:
39 |
40 | ```shell
41 | # For all pods in the namespace run
42 | stern --kubeconfig .cache/config --namespace dsv --timestamps .
43 |
44 | # For pods with the selector run
45 | stern --kubeconfig .cache/config --namespace dsv --timestamps --selector 'dsv-filter-name in (dsv-syncer, dsv-injector)'
46 | ```
47 |
48 | ### Example for Providing Logs for Support
49 |
50 | If debugging, you can stream logs from Kubernetes with this tool and capture to a log file for providing in support cases.
51 |
52 | ```shell
53 | stern --kubeconfig .cache/config --namespace dsv --timestamps . > activity.log
54 | ```
55 |
--------------------------------------------------------------------------------
/docs/using.md:
--------------------------------------------------------------------------------
1 | # Using
2 |
3 | Once installed, any correctly annotated Kubernetes Secrets are modified on create and update.
4 |
5 | The four annotations that affect the behavior of the webhook are:
6 |
7 | ```golang
8 | const(
9 | credentialsAnnotation = "dsv.delinea.com/credentials"
10 | setAnnotation = "dsv.delinea.com/set-secret"
11 | addAnnotation = "dsv.delinea.com/add-to-secret"
12 | updateAnnotation = "dsv.delinea.com/update-secret"
13 | )
14 | ```
15 |
16 | `credentialsAnnotation` selects the credentials that the injector uses to retrieve the DSV Secret.
17 | If the credentials are present, it must map to Client Credential and Tenant mapping.
18 | The injector will use the _default_ Credential and Tenant mapping unless the `credentialsAnnotation` is declared.
19 | The `setAnnotation`, `addAnnotation` and `updateAnnotation`, must contain the path to the DSV Secret that the injector will use to mutate the Kubernetes Secret.
20 |
21 | - `addAnnotation` adds missing fields without overwriting or removing existing fields.
22 | - `updateAnnotation` adds and overwrites existing fields but does not remove fields.
23 | - `setAnnotation` overwrites fields and removes fields that do not exist in the DSV Secret.
24 | NOTE: A Kubernetes Secret should specify only one of the "add," "update,"
25 | or "set" annotations.
26 | The order of precedence is `setAnnotation`,
27 | then `addAnnotation`, then `updateAnnotation` when multiple are present.
28 |
29 | ## Examples
30 |
31 | ```yaml
32 | ---
33 | apiVersion: v1
34 | kind: Secret
35 | metadata:
36 | name: example-secret
37 | annotations:
38 | dsv.delinea.com/credentials: app1
39 | dsv.delinea.com/set-secret: test:secret
40 | type: Opaque
41 | data:
42 | username:
43 | domain:
44 | password:
45 | ```
46 |
47 | The above example specifies credentials, so a mapping for those credentials must exist in the current webhook configuration.
48 | It uses the `setAnnotation`, so the data in the injector will overwrite the existing contents of the Kubernetes Secret.
49 |
50 | If `/test/secret` contains a `username` and `password` but no `domain`, then the k8s secret would get the `username` and `password` from dsv secret data and the injector will remove the `domain` field.
51 |
52 | There are more examples in the `examples` directory.
53 | They show how the different annotations work.
54 |
--------------------------------------------------------------------------------
/examples/add-to-secret.yml:
--------------------------------------------------------------------------------
1 | # trunk-ignore-all(trivy,checkov,gitleaks): ignore, examples file with hard coded values
2 | ---
3 | apiVersion: v1
4 | kind: Secret
5 | metadata:
6 | name: user-domain
7 | annotations:
8 | dsv.delinea.com/add-to-secret: 'tests:dsv-k8s:food'
9 | type: Opaque
10 | data:
11 | username: dW5tb2RpZmllZC11c2VybmFtZQ==
12 | domain: dW5tb2RpZmllZC1kb21haW4=
13 | food: aW0gaHVuZ3J5IGFuZCB0aGlzIHNob3VsZCBiZSByZXBsYWNlZCB3aXRoIGdvb2QgZm9vZAo=
14 |
--------------------------------------------------------------------------------
/examples/set-secret.yml:
--------------------------------------------------------------------------------
1 | # trunk-ignore-all(trivy,checkov,gitleaks): ignore, examples file with hard coded values
2 | ---
3 | apiVersion: v1
4 | kind: Secret
5 | metadata:
6 | name: user-domain-pass
7 | annotations:
8 | # dsv.delinea.com/credentials: app1 # or default if not using multiple credentials
9 | dsv.delinea.com/set-secret: 'tests:dsv-k8s:food'
10 | type: Opaque
11 | data:
12 | username: dW5tb2RpZmllZC11c2VybmFtZQ==
13 | domain: dW5tb2RpZmllZC1kb21haW4=
14 | password: dW5tb2RpZmllZC1wYXNzd29yZA==
15 | food: aW0gaHVuZ3J5IGFuZCB0aGlzIHNob3VsZCBiZSByZXBsYWNlZCB3aXRoIGdvb2QgZm9vZAo=
16 |
--------------------------------------------------------------------------------
/examples/update-secret.yml:
--------------------------------------------------------------------------------
1 | # trunk-ignore-all(trivy,checkov,gitleaks): ignore, examples file with hard coded values
2 | ---
3 | apiVersion: v1
4 | kind: Secret
5 | metadata:
6 | name: pass-domain
7 | annotations:
8 | dsv.delinea.com/update-secret: 'tests:dsv-k8s:food'
9 | type: Opaque
10 | data:
11 | password: dW5tb2RpZmllZC1wYXNzd29yZA==
12 | domain: dW5tb2RpZmllZC1kb21haW4=
13 | food: aW0gaHVuZ3J5IGFuZCB0aGlzIHNob3VsZCBiZSByZXBsYWNlZCB3aXRoIGdvb2QgZm9vZAo=
14 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/DelineaXPM/dsv-k8s/v2
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.24.1
6 |
7 | require (
8 | al.essio.dev/pkg/shellescape v1.5.0
9 | github.com/DelineaXPM/dsv-sdk-go/v2 v2.1.2
10 | github.com/bitfield/script v0.22.1
11 | github.com/brianvoe/gofakeit/v6 v6.28.0
12 | github.com/caarlos0/env/v6 v6.10.1
13 | github.com/magefile/mage v1.15.0
14 | github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38
15 | github.com/pterm/pterm v0.12.79
16 | github.com/rs/zerolog v1.33.0
17 | github.com/sheldonhull/magetools v1.0.2
18 | k8s.io/api v0.30.3
19 | k8s.io/apimachinery v0.30.3
20 | k8s.io/client-go v0.30.3
21 | )
22 |
23 | require (
24 | atomicgo.dev/cursor v0.2.0 // indirect
25 | atomicgo.dev/keyboard v0.2.9 // indirect
26 | atomicgo.dev/schedule v0.1.0 // indirect
27 | github.com/aws/aws-sdk-go v1.55.5 // indirect
28 | github.com/containerd/console v1.0.4 // indirect
29 | github.com/davecgh/go-spew v1.1.1 // indirect
30 | github.com/dustin/go-humanize v1.0.1 // indirect
31 | github.com/emicklei/go-restful/v3 v3.12.1 // indirect
32 | github.com/go-logr/logr v1.4.2 // indirect
33 | github.com/go-openapi/jsonpointer v0.21.0 // indirect
34 | github.com/go-openapi/jsonreference v0.21.0 // indirect
35 | github.com/go-openapi/swag v0.23.0 // indirect
36 | github.com/gogo/protobuf v1.3.2 // indirect
37 | github.com/golang/protobuf v1.5.4 // indirect
38 | github.com/google/gnostic-models v0.6.8 // indirect
39 | github.com/google/gofuzz v1.2.0 // indirect
40 | github.com/google/uuid v1.6.0 // indirect
41 | github.com/gookit/color v1.5.4 // indirect
42 | github.com/imdario/mergo v0.3.12 // indirect
43 | github.com/itchyny/gojq v0.12.16 // indirect
44 | github.com/itchyny/timefmt-go v0.1.6 // indirect
45 | github.com/jmespath/go-jmespath v0.4.0 // indirect
46 | github.com/josharian/intern v1.0.0 // indirect
47 | github.com/json-iterator/go v1.1.12 // indirect
48 | github.com/lithammer/fuzzysearch v1.1.8 // indirect
49 | github.com/mailru/easyjson v0.7.7 // indirect
50 | github.com/mattn/go-colorable v0.1.13 // indirect
51 | github.com/mattn/go-isatty v0.0.20 // indirect
52 | github.com/mattn/go-runewidth v0.0.16 // indirect
53 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
54 | github.com/modern-go/reflect2 v1.0.2 // indirect
55 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
56 | github.com/rivo/uniseg v0.4.7 // indirect
57 | github.com/spf13/pflag v1.0.5 // indirect
58 | github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
59 | github.com/ztrue/tracerr v0.4.0 // indirect
60 | golang.org/x/mod v0.20.0 // indirect
61 | golang.org/x/net v0.38.0 // indirect
62 | golang.org/x/oauth2 v0.27.0 // indirect
63 | golang.org/x/sys v0.31.0 // indirect
64 | golang.org/x/term v0.30.0 // indirect
65 | golang.org/x/text v0.23.0 // indirect
66 | golang.org/x/time v0.6.0 // indirect
67 | google.golang.org/protobuf v1.34.2 // indirect
68 | gopkg.in/inf.v0 v0.9.1 // indirect
69 | gopkg.in/yaml.v2 v2.4.0 // indirect
70 | gopkg.in/yaml.v3 v3.0.1 // indirect
71 | k8s.io/klog/v2 v2.130.1 // indirect
72 | k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8 // indirect
73 | k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
74 | mvdan.cc/sh/v3 v3.8.0 // indirect
75 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
76 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
77 | sigs.k8s.io/yaml v1.4.0 // indirect
78 | )
79 |
80 | replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16
81 |
--------------------------------------------------------------------------------
/internal/k8s/k8s.go:
--------------------------------------------------------------------------------
1 | package k8s
2 |
3 | import (
4 | "fmt"
5 |
6 | "k8s.io/client-go/kubernetes"
7 | v1 "k8s.io/client-go/kubernetes/typed/core/v1"
8 | "k8s.io/client-go/rest"
9 | )
10 |
11 | // Config is a callback that returns a Kubernetes Client API config for the given namespace; namespace = "" for all namespaces.
12 | // see https://github.com/kubernetes/client-go/tree/v0.23.5/examples
13 | type Config func(namespace string) (*rest.Config, error)
14 |
15 | func GetKubernetesClientset(configCallback Config, namespace string) (*kubernetes.Clientset, error) {
16 | if config, err := configCallback(namespace); err != nil {
17 | return nil, fmt.Errorf("[ERROR] error calling k8s.Config: %s", err)
18 | } else {
19 | if clientset, err := kubernetes.NewForConfig(config); err != nil {
20 | return nil, fmt.Errorf("[ERROR] error getting Kubernetes Clientset: %s", err)
21 | } else {
22 | return clientset, nil
23 | }
24 | }
25 | }
26 |
27 | // getSecretsClient returns a Kubernetes Secrets client for the given namespace; namespace = "" for all namespaces.
28 | func GetSecretsClient(configCallback Config, namespace string) (v1.SecretInterface, error) {
29 | if clientset, err := GetKubernetesClientset(configCallback, namespace); err != nil {
30 | return nil, fmt.Errorf("[ERROR] error getting Kubernetes Clientset: %s", err)
31 | } else {
32 | return clientset.CoreV1().Secrets(namespace), nil
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/internal/logger/logger.go:
--------------------------------------------------------------------------------
1 | // logger handles setting the default output format for logging
2 | package logger
3 |
4 | import (
5 | "os"
6 | "strconv"
7 |
8 | "github.com/rs/zerolog"
9 | )
10 |
11 | // var Logger zerolog.Logger //nolint:gochecknoglobals // allow for logging at this time.
12 |
13 | // InitLogger initializes the zerolog logger settings.
14 | func New() zerolog.Logger {
15 | // see zerolog docs, this removes the fully qualified path and makes it just show the "logger.go:linenumber" so logs are much easier to read
16 | zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
17 | short := file
18 | for i := len(file) - 1; i > 0; i-- {
19 | if file[i] == '/' {
20 | short = file[i+1:]
21 | break
22 | }
23 | }
24 | file = short
25 | return file + ":" + strconv.Itoa(line)
26 | }
27 | l := zerolog.New(os.Stdout).With().Caller().Logger().With().Timestamp().Logger()
28 | zerolog.SetGlobalLevel(zerolog.InfoLevel)
29 | return l
30 | }
31 |
32 | // EnableDebug enables debug logging.
33 | func EnableDebug() {
34 | zerolog.SetGlobalLevel(zerolog.DebugLevel)
35 | }
36 |
--------------------------------------------------------------------------------
/internal/test/testing.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "io"
5 | "log"
6 | "os"
7 | "testing"
8 |
9 | "github.com/DelineaXPM/dsv-k8s/v2/pkg/config"
10 | )
11 |
12 | const (
13 | ConfigEnvVar = "DSV_K8S_TEST_CONFIG"
14 | ConfigFileEnvVar = "DSV_K8S_TEST_CONFIG_FILE"
15 | DefaultConfigFile = "../../configs/credentials.json"
16 | DefaultSecretPath = "/test/secret"
17 | SecretPathEnvVar = "DSV_K8S_TEST_SECRET_PATH"
18 | )
19 |
20 | // Ensure log output doesn't pollute tests.
21 | func TestMain(m *testing.M) {
22 | log.SetOutput(io.Discard)
23 | }
24 |
25 | // SecretPath returns the secret path for testing
26 | func SecretPath() string {
27 | if v := os.Getenv(SecretPathEnvVar); v != "" {
28 | return v
29 | }
30 | return DefaultSecretPath
31 | }
32 |
33 | func credentialsFromFilePath(credentialsFilePath string) config.Credentials {
34 | if credentials, err := config.GetCredentials(credentialsFilePath); err == nil {
35 | return *credentials
36 | } else {
37 | panic(err)
38 | }
39 | }
40 |
41 | // Credentials returns the credentials for testing
42 | func Credentials() config.Credentials {
43 | if v := os.Getenv(ConfigEnvVar); v != "" {
44 | if credentials, err := config.MakeCredentials([]byte(v)); err == nil {
45 | return *credentials
46 | } else {
47 | panic(err) // FIXME: avoid using panic and error out gracefully
48 | }
49 | } else if v := os.Getenv(ConfigFileEnvVar); v != "" {
50 | return credentialsFromFilePath(v)
51 | } else {
52 | return credentialsFromFilePath(DefaultConfigFile)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/magefiles/constants/constants.mage.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | // Since we are dealing with builds, having a constants file until using a config input makes it easy.
4 |
5 | // Default target to run when none is specified
6 | // If not set, running mage will list available targets
7 | // var Default = Build.
8 |
9 | const (
10 | // ArtifactDirectory is a directory containing artifacts for the project and shouldn't be committed to source.
11 | ArtifactDirectory = ".artifacts"
12 |
13 | // PermissionUserReadWriteExecute is the permissions for the artifact directory.
14 | PermissionUserReadWriteExecute = 0o0700
15 |
16 | // ConfigsDirectory is where the credentials used for testing is placed.
17 | // This isn't committed in git.
18 | ConfigsDirectory = "configs"
19 |
20 | // CacheDirectory is where the cache for the project is placed, ie artifacts that don't need to be rebuilt often.
21 | CacheDirectory = ".cache"
22 |
23 | // ExamplesDirectory is the directory where the kubernetes manifests are stored.
24 | ExamplesDirectory = "examples"
25 |
26 | // CacheChartsDirectory is the directory where the cached helm values file is copied to.
27 | CacheChartsDirectory = ".cache/charts"
28 |
29 | // CacheCredentialFile is the path to the credential file for the project, which is cached locally.
30 | CacheCredentialFile = ".cache/credentials.json" //nolint:gosec // this is a test project and this directory is excluded from source
31 | )
32 |
33 | const (
34 | // KindClusterName is the name of the kind cluster.
35 | KindClusterName = "dsvtest"
36 | // KindClusterName is the name of the kind cluster.
37 | KindContextName = "dsvtest"
38 | // KubeconfigPath is the path to the kubeconfig file for this project, which is cached locally.
39 | Kubeconfig = ".cache/config"
40 | // KubectlNamespace is the namespace used for all kubectl commands, so that they don't operate in default or other namespace by accident.
41 | KubectlNamespace = "dsv"
42 |
43 | // DockerImageQualified is the qualified path of the image in Docker Hub.
44 | DockerImageQualified = "docker.io/delineaxpm/dsv-k8s"
45 | // DockerImageNameLocal is the name of the built image to run locally and load with minikube/kind.
46 | DockerImageNameLocal = "dev.local/dsv-k8s"
47 | )
48 |
49 | const (
50 |
51 | // HelmTimeout is the timeout for helm commands using the CLI.
52 | HelmTimeout = "5m"
53 | // ChartsDirectory is the directory where the helm charts are placed, in sub directories.
54 | ChartsDirectory = "charts"
55 | // SternFilter is the filter for dsv-filter-name for streaming logs easily.
56 | SternFilter = "dsv-syncer, dsv-injector"
57 | )
58 |
59 | const (
60 | // MinikubeCPU is the CPU count for minikube.
61 | MinikubeCPU = "2"
62 | // MinikubeMemory is the memory for minikube.
63 | MinikubeMemory = "2048"
64 | )
65 |
--------------------------------------------------------------------------------
/magefiles/constants/variables.mage.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | import (
4 | "path/filepath"
5 | "time"
6 | )
7 |
8 | type HelmCharts struct {
9 | ReleaseName string
10 | ChartPath string
11 | Namespace string
12 | // Values is the customized yaml file placed in the CacheDirectory to run install with.
13 | // Copy the values.yaml from the helm chart to start here.
14 | Values string
15 | }
16 |
17 | var HelmChartsList = []HelmCharts{
18 | {
19 | ReleaseName: "dsv-syncer",
20 | ChartPath: filepath.Join(ChartsDirectory, "dsv-syncer"),
21 | Namespace: "dsv",
22 | Values: filepath.Join(CacheDirectory, "dsv-syncer", "values.yaml"),
23 | },
24 | {
25 | ReleaseName: "dsv-injector",
26 | ChartPath: filepath.Join(ChartsDirectory, "dsv-injector"),
27 | Namespace: "dsv",
28 | Values: filepath.Join(CacheDirectory, "dsv-injector", "values.yaml"),
29 | },
30 | }
31 |
32 | // DefaultHelmTimeoutMinutes is the default timeout for helm commands.
33 | var DefaultHelmTimeoutMinutes = time.Minute * 5
34 |
35 | // CacheManifestDirectory is the directory where helm charts are cached for local tweaking.
36 | // They are copied from the examples directory to allow editing without committing to source control.
37 | var CacheManifestDirectory = filepath.Join(CacheDirectory, "manifests")
38 |
--------------------------------------------------------------------------------
/magefiles/dev-cli-tools.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | // ToolList is a list of tools that are installed as binaries for development usage.
4 | // This list gets installed to go bin directory once `mage init` is run.
5 | var ToolList = []string{}
6 |
--------------------------------------------------------------------------------
/magefiles/goreleaser.mage.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "hash"
6 | "hash/fnv"
7 | "os"
8 | "path/filepath"
9 | "strings"
10 | "time"
11 |
12 | "github.com/brianvoe/gofakeit/v6"
13 | "github.com/magefile/mage/sh"
14 | "github.com/pterm/pterm"
15 | "github.com/sheldonhull/magetools/pkg/magetoolsutils"
16 | "github.com/sheldonhull/magetools/pkg/req"
17 | )
18 |
19 | // FNV64a hashes using fnv64a algorithm
20 | //
21 | // Sourced from: https://github.com/shomali11/util/blob/master/xhashes/xhashes.go
22 | func FNV64a(text string) uint64 {
23 | algorithm := fnv.New64a()
24 | return uint64Hasher(algorithm, text)
25 | }
26 |
27 | // uint64Hasher returns a uint64
28 | //
29 | // Sourced from: https://github.com/shomali11/util/blob/master/xhashes/xhashes.go
30 | func uint64Hasher(algorithm hash.Hash64, text string) uint64 {
31 | algorithm.Write([]byte(text))
32 | return algorithm.Sum64()
33 | }
34 |
35 | func randomBuildName() (petname string) {
36 | v := time.Now().Unix()
37 | gofakeit.Seed(v)
38 | animal := gofakeit.Animal()
39 | adjective := gofakeit.AdjectiveDescriptive()
40 | petname = strings.ToLower(strings.Join([]string{adjective, animal}, "-"))
41 | pterm.Info.Printfln("Random Pet Calculated at Runtime: %s\n", petname)
42 |
43 | return petname
44 | }
45 |
46 | func checkEnvVar(envVar string, required bool) (string, error) {
47 | envVarValue := os.Getenv(envVar)
48 | if envVarValue == "" && required {
49 | pterm.Error.Printfln(
50 | "%s is required and unable to proceed without this being provided. terminating task.",
51 | envVar,
52 | )
53 | return "", fmt.Errorf("%s is required", envVar)
54 | }
55 | if envVarValue == "" {
56 | pterm.Debug.Printfln(
57 | "checkEnvVar() found no value for: %q, however this is marked as optional, so not exiting task",
58 | envVar,
59 | )
60 | }
61 | pterm.Debug.Printfln("checkEnvVar() found value: %q=%q", envVar, envVarValue)
62 | return envVarValue, nil
63 | }
64 |
65 | // 🔨 Build builds the project for the current platform.
66 | func Build() error {
67 | magetoolsutils.CheckPtermDebug()
68 | binary, err := req.ResolveBinaryByInstall("goreleaser", "github.com/goreleaser/goreleaser@latest")
69 | if err != nil {
70 | return err
71 | }
72 |
73 | releaserArgs := []string{
74 | "build",
75 | "--clean",
76 | "--snapshot",
77 | "--single-target",
78 | }
79 | pterm.Debug.Printfln("goreleaser: %+v", releaserArgs)
80 |
81 | return sh.RunWithV(
82 | map[string]string{
83 | "BUILD_NAME": randomBuildName(),
84 | },
85 | binary, releaserArgs...) // "--skip-announce",.
86 | }
87 |
88 | // 🔨 BuildAll builds all the binaries defined in the project, for all platforms. This includes Docker image generation but skips publish.
89 | // If there is no additional platforms configured in the task, then basically this will just be the same as `mage build`.
90 | func BuildAll() error {
91 | magetoolsutils.CheckPtermDebug()
92 | binary, err := req.ResolveBinaryByInstall("goreleaser", "github.com/goreleaser/goreleaser@latest")
93 | if err != nil {
94 | return err
95 | }
96 |
97 | releaserArgs := []string{
98 | "release",
99 | "--snapshot",
100 | "--clean",
101 | "--skip", "publish,sbom",
102 | }
103 | pterm.Debug.Printfln("goreleaser: %+v", releaserArgs)
104 | _ = os.Setenv("BUILD_NAME", randomBuildName())
105 | return sh.RunWithV(
106 | map[string]string{
107 | "BUILD_NAME": randomBuildName(),
108 | }, binary, releaserArgs...)
109 | // To pass in explicit version mapping, you can do this. I'm not using at this time.
110 | // Return sh.RunWithV(map[string]string{
111 | // "GORELEASER_CURRENT_TAG": "latest",
112 | // }, binary, releaserArgs...)
113 | }
114 |
115 | // 🔨 Release generates a release for the current platform.
116 | func Release() error {
117 | magetoolsutils.CheckPtermDebug()
118 | binary, err := req.ResolveBinaryByInstall("goreleaser", "github.com/goreleaser/goreleaser@latest")
119 | if err != nil {
120 | return err
121 | }
122 |
123 | if _, err = checkEnvVar("DOCKER_ORG", true); err != nil {
124 | return err
125 | }
126 |
127 | changieBinary, err := req.ResolveBinaryByInstall("changie", "github.com/miniscruff/changie@latest")
128 | if err != nil {
129 | pterm.Error.Println("unable to install changelog binary")
130 | return err
131 | }
132 | releaseVersion, err := sh.Output(changieBinary, "latest")
133 | if err != nil {
134 | pterm.Warning.Printfln("changie pulling latest release note version failure: %v", err)
135 | }
136 | cleanVersion := strings.TrimSpace(releaseVersion)
137 | cleanpath := filepath.Join(".changes", cleanVersion+".md")
138 | if os.Getenv("GITHUB_WORKSPACE") != "" {
139 | cleanpath = filepath.Join(os.Getenv("GITHUB_WORKSPACE"), ".changes", cleanVersion+".md")
140 | }
141 |
142 | releaserArgs := []string{
143 | "release",
144 | "--clean",
145 | "--skip=validate",
146 | fmt.Sprintf("--release-notes=%s", cleanpath),
147 | }
148 | pterm.Debug.Printfln("goreleaser: %+v", releaserArgs)
149 |
150 | return sh.RunWithV(
151 | map[string]string{
152 | "GORELEASER_CURRENT_TAG": cleanVersion,
153 | "BUILD_NAME": randomBuildName(),
154 | },
155 | binary,
156 | releaserArgs...,
157 | )
158 | }
159 |
--------------------------------------------------------------------------------
/magefiles/install.mage.go:
--------------------------------------------------------------------------------
1 | package main
2 |
--------------------------------------------------------------------------------
/magefiles/jobs.mage.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/DelineaXPM/dsv-k8s/v2/magefiles/constants"
5 | "github.com/DelineaXPM/dsv-k8s/v2/magefiles/helm"
6 | "github.com/DelineaXPM/dsv-k8s/v2/magefiles/k8s"
7 | // "github.com/DelineaXPM/dsv-k8s/v2/magefiles/kind"
8 | "github.com/DelineaXPM/dsv-k8s/v2/magefiles/minikube"
9 | "github.com/magefile/mage/mg"
10 | "github.com/pterm/pterm"
11 | )
12 |
13 | // Job is a namespace to contain chained sets of automation actions, to reduce the need to chain many commands together for common workflows.
14 | type Job mg.Namespace
15 |
16 | // Init runs the setup tasks to initialize the local resources and files, without trying to apply yet.
17 | //
18 | // Setup initializes all the required steps for the cluster creation, initial helm chart copies, and kubeconfig copies.
19 | func (Job) Init() {
20 | pterm.DefaultSection.Println("(Job) Init()")
21 | mg.SerialDeps(
22 | // kind.Kind{}.Init,
23 | minikube.Minikube{}.Init,
24 | k8s.K8s{}.Init,
25 | helm.Helm{}.Init,
26 | )
27 | }
28 |
29 | // Redeploy removes k8s resources, helm uninstall, and then runs k8s apply and helm install.
30 | func (Job) Redeploy() {
31 | pterm.DefaultSection.Println("(Job) Redeploy()")
32 |
33 | mg.Deps(
34 | helm.Helm{}.Uninstall,
35 | mg.F(k8s.K8s{}.Delete, constants.CacheManifestDirectory),
36 | )
37 |
38 | mg.SerialDeps(
39 | minikube.Minikube{}.RemoveImages,
40 | minikube.Minikube{}.LoadImages, // just be sure in case forget to load local images that the latest is always used
41 | helm.Helm{}.Install, // this should take place first so the creation of the manifests can benefit from the resulting injector/syncer
42 | mg.F(k8s.K8s{}.Apply, constants.CacheManifestDirectory),
43 | // k8s.K8s{}.Logs, // use chained command
44 | )
45 | }
46 |
47 | // RebuildImages runs the build and minikube load commands so the new source is able to be run by `job:redeploy`.
48 | func (Job) RebuildImages() {
49 | pterm.DefaultSection.Println("(Job) RebuildImages()")
50 | mg.SerialDeps(
51 | BuildAll,
52 | minikube.Minikube{}.LoadImages,
53 | )
54 | pterm.Success.Printfln("RebuildImages() complete. Run `mage job:redeploy` to redeploy the new images.")
55 | }
56 |
--------------------------------------------------------------------------------
/magefiles/k8s/k8s.mage.go:
--------------------------------------------------------------------------------
1 | // K8s contains commands for kubectl and other kubernetes related commands.
2 | package k8s
3 |
4 | import (
5 | "encoding/base64"
6 | "errors"
7 | "fmt"
8 | "os"
9 | "os/exec"
10 | "path/filepath"
11 | "strings"
12 |
13 | "github.com/DelineaXPM/dsv-k8s/v2/magefiles/constants"
14 | "github.com/magefile/mage/mg"
15 | "github.com/magefile/mage/sh"
16 | "github.com/pterm/pterm"
17 | "github.com/sheldonhull/magetools/pkg/magetoolsutils"
18 | )
19 |
20 | // k8s contains commands for kubectl and other kubernetes related commands.
21 | type K8s mg.Namespace
22 |
23 | // Init copies the k8 yaml manifest files from the examples directory to the cache directory.
24 | func (K8s) Init() error {
25 | magetoolsutils.CheckPtermDebug()
26 | pterm.DefaultHeader.Println("(K8s) Init()")
27 | // Create the cache directory if it doesn't exist.
28 | if _, err := os.Stat(constants.CacheManifestDirectory); os.IsNotExist(err) {
29 | if err := os.MkdirAll(constants.CacheManifestDirectory, constants.PermissionUserReadWriteExecute); err != nil {
30 | return fmt.Errorf("os.MkdirAll(): %w", err)
31 | }
32 | }
33 | // For each file in the examples directory, create a copy in the CacheManifestDirectory.
34 | de, err := os.ReadDir(constants.ExamplesDirectory)
35 | if err != nil {
36 | return err
37 | }
38 | for _, file := range de {
39 | originalFile := filepath.Join(constants.ExamplesDirectory, file.Name())
40 | targetFile := filepath.Join(constants.CacheManifestDirectory, file.Name())
41 | // If the file doesn't exist in the manifest directory, read it and copy it to the manifest directory.
42 | if _, err := os.Stat(targetFile); os.IsNotExist(err) {
43 | // Read the original file.
44 | original, err := os.ReadFile(originalFile)
45 | if err != nil {
46 | return fmt.Errorf("unable to read original file: %s, os.ReadFile(): %w", original, err)
47 | }
48 | // Create the new file from the contents of the original file.
49 | if err := os.WriteFile(targetFile, original, constants.PermissionUserReadWriteExecute); err != nil {
50 | return fmt.Errorf("unable to write new file: %s, os.WriteFile(): %w", targetFile, err)
51 | }
52 | pterm.Success.Printfln("copied starter example (edit and apply to use): %s", targetFile)
53 | }
54 | }
55 | pterm.Success.Println("(K8s) Init()")
56 | return nil
57 | }
58 |
59 | // Apply applies a kubernetes manifest.
60 | func (K8s) Apply(manifest string) error {
61 | magetoolsutils.CheckPtermDebug()
62 | pterm.DefaultHeader.Println("(K8s) Apply()")
63 | return sh.Run(
64 | "kubectl",
65 | "apply",
66 | "--kubeconfig", constants.Kubeconfig,
67 | "--context", constants.KindContextName,
68 | "--namespace", constants.KubectlNamespace,
69 | "--cluster", constants.KindContextName,
70 | "--wait=true",
71 | "--overwrite=true",
72 | "-f", manifest,
73 | )
74 | }
75 |
76 | // Apply applies a kubernetes manifest.
77 | func (K8s) Delete(manifest string) {
78 | magetoolsutils.CheckPtermDebug()
79 | pterm.DefaultHeader.Println("(K8s) Delete()")
80 | if err := sh.Run(
81 | "kubectl",
82 | "delete",
83 | "--kubeconfig", constants.Kubeconfig,
84 | "--context", constants.KindContextName,
85 | "--namespace", constants.KubectlNamespace,
86 | "--cluster", constants.KindContextName,
87 | "-f", manifest,
88 | ); err != nil {
89 | pterm.Warning.Printfln("(K8s) Delete() error [non-terminating]: %s", err)
90 | }
91 | }
92 |
93 | // Logs streams logs until canceled for the dsv syncing jobs, based on the label `dsv.delinea.com: syncer`.
94 | func (K8s) Logs() error {
95 | magetoolsutils.CheckPtermDebug()
96 | if _, err := exec.LookPath("stat"); err != nil {
97 | pterm.Error.Printfln("install stern tool manually (see .devcontainer/Dockerfile for install command) to run this")
98 | return errors.New("stern tool not installed yet")
99 | }
100 | pterm.DefaultHeader.Println("(K8s) Logs()")
101 | pterm.Info.Printfln("if you run into log output issues, just try running:\n\n\t\tkubectl logs --context %s --namespace %s --selector 'dsv-filter-name in (dsv-syncer, dsv-injector)' --follow --prefix\n", constants.KindContextName, constants.KubectlNamespace)
102 | pterm.Info.Println("🔍 query without selector:\n\n\tstern --kubeconfig .cache/config --namespace dsv --timestamps . ")
103 | pterm.Info.Println(
104 | "🔍 Manually run stern with the following:\n\n\t",
105 | "stern",
106 | "--namespace", constants.KubectlNamespace,
107 | "--timestamps",
108 | "--selector", "dsv-filter-name in (dsv-syncer, dsv-injector)",
109 | )
110 |
111 | pterm.Info.Println(
112 | "🔍 Manually run stern againt entire cluster with following:\n\n\t",
113 | "stern",
114 | "--all-namespaces",
115 | "--timestamps",
116 | ".",
117 | )
118 | pterm.DefaultHeader.Println("kubectl output first")
119 | _ = sh.RunV("kubectl",
120 | "logs",
121 | "--kubeconfig", constants.Kubeconfig,
122 | "--context", constants.KindContextName,
123 | "--namespace", constants.KubectlNamespace,
124 | "--cluster", constants.KindContextName,
125 | "--selector", "dsv-filter-name in (dsv-syncer, dsv-injector)",
126 | // "--follow",
127 | "--since=5m",
128 | "--prefix",
129 | )
130 | pterm.DefaultHeader.Println("stern streaming output")
131 | return sh.RunV(
132 | "stern",
133 | "--namespace", constants.KubectlNamespace,
134 | "--timestamps",
135 | "--selector", "dsv-filter-name in (dsv-syncer, dsv-injector)",
136 | )
137 | }
138 |
139 | // 🔍 OutputSecret outputs the base64 decoded values for local minikube style testing.
140 | func (K8s) OutputSecret() {
141 | magetoolsutils.CheckPtermDebug()
142 | for _, secretname := range []string{"user-domain-pass", "user-domain", "pass-domain"} {
143 | response, err := sh.Output(
144 | "kubectl",
145 | "--kubeconfig", constants.Kubeconfig,
146 | "--context", constants.KindContextName,
147 | "--namespace", constants.KubectlNamespace,
148 | "--cluster", constants.KindContextName,
149 | "get",
150 | "secret", secretname,
151 | "-o", `go-template={{.data.password}}`,
152 | "--ignore-not-found",
153 | )
154 | if err != nil {
155 | pterm.Warning.Printfln("not able to find this %q: %v", secretname, err)
156 | } else {
157 | cleanedoutput := strings.TrimSpace(response)
158 | b, err := base64.StdEncoding.DecodeString(cleanedoutput)
159 | if err != nil {
160 | pterm.Warning.Printfln("issue decoding string: %v", err)
161 | pterm.Debug.Printfln(
162 | "kubectl --kubeconfig %s --context %s --namespace %s --cluster %s get secret %s -o go-template='{{.data.password}}' --ignore-not-found",
163 | constants.Kubeconfig,
164 | constants.KindContextName,
165 | constants.KubectlNamespace,
166 | constants.KindContextName,
167 | secretname,
168 | )
169 | } else {
170 | pterm.Info.Printfln("🔑 [only for local testing] %q: %q", secretname, string(b)) // ♥️ nested if statements 😀
171 | }
172 | }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/magefiles/kind-3-nodes.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Cluster
3 | apiVersion: kind.x-k8s.io/v1alpha4
4 | # One control plane node and three "workers".
5 | #
6 | # While these will not add more real compute capacity and
7 | # have limited isolation, this can be useful for testing
8 | # rolling updates etc.
9 | #
10 | # The API-server and other control plane components will be
11 | # on the control-plane node.
12 | #
13 | # You probably don't need this unless you are testing Kubernetes itself.
14 | nodes:
15 | - role: control-plane
16 | - role: worker
17 | - role: worker
18 | - role: worker
19 |
--------------------------------------------------------------------------------
/magefiles/kind/kind.mage.go:
--------------------------------------------------------------------------------
1 | // Kind package contains all the tasks for automation of kind cluster creation and tear down, and the required kubectl commands to correctly use this.
2 | package kind
3 |
4 | import (
5 | "fmt"
6 | "os"
7 | "regexp"
8 | "strings"
9 | "time"
10 |
11 | "github.com/DelineaXPM/dsv-k8s/v2/magefiles/constants"
12 |
13 | "github.com/magefile/mage/mg"
14 | "github.com/magefile/mage/sh"
15 | "github.com/pterm/pterm"
16 | mtu "github.com/sheldonhull/magetools/pkg/magetoolsutils"
17 | )
18 |
19 | // Kind contains the kind cli commands.
20 | type Kind mg.Namespace
21 |
22 | func createCluster() error {
23 | mtu.CheckPtermDebug()
24 | kindargs := []string{
25 | "create",
26 | "cluster",
27 | "--name", constants.KindClusterName,
28 | "--wait",
29 | "300s",
30 | }
31 | if os.Getenv("KIND_SETUP_CONFIG") != "" {
32 | pterm.Info.Printfln("KIND_SETUP_CONFIG: %s", os.Getenv("KIND_SETUP_CONFIG"))
33 | kindargs = append(kindargs, "--config", os.Getenv("KIND_SETUP_CONFIG"))
34 | }
35 | if err := sh.RunV(
36 | "kind",
37 | kindargs...,
38 | ); err != nil {
39 | return err
40 | }
41 | return nil
42 | }
43 |
44 | func updateKubeconfig() error {
45 | mtu.CheckPtermDebug()
46 | if _, err := os.Stat(constants.Kubeconfig); os.IsNotExist(err) {
47 | if _, err := os.Create(constants.Kubeconfig); err != nil {
48 | pterm.Error.Printfln("unable to create empty placeholder file: %v", err)
49 | }
50 | }
51 | kc, err := sh.Output("kind", "get", "cluster", "kubeconfig", "--name", constants.KindClusterName)
52 | if err != nil {
53 | pterm.Error.Println("unable to get kind cluster info, maybe you need to run mage kind:init first?")
54 | return err
55 | }
56 |
57 | if err := os.WriteFile(constants.Kubeconfig, []byte(kc), constants.PermissionUserReadWriteExecute); err != nil {
58 | pterm.Error.Printfln("unable to write kubeconfig to file: %v", err)
59 | return err
60 | }
61 | pterm.Info.Printfln("kubeconfig updated: %s", constants.Kubeconfig)
62 | // for now this is only going to be run against Kind cluster.
63 | // if err := sh.Run(
64 | // "kubectl",
65 | // "cluster-info", "--context", constants.KindContextName,
66 | // "--cluster", constants.KindContextName,
67 | // ); err != nil {
68 | // return err
69 | // }
70 | return nil
71 | }
72 |
73 | // ➕ Create creates a new Kind cluster and populates a kubeconfig in cachedirectory.
74 | func (Kind) Init() error {
75 | mtu.CheckPtermDebug()
76 |
77 | out, err := sh.Output("kind", "get", "clusters")
78 | if err := err; err != nil {
79 | return err
80 | }
81 | cleanOutput := strings.TrimSpace(out)
82 | matchedCluster := regexp.MustCompile(constants.KindClusterName)
83 | pterm.Debug.Printfln("cleanOutput: %s", cleanOutput)
84 | if !matchedCluster.MatchString(cleanOutput) {
85 | pterm.Info.Printfln("simple match not found, so attempting to recreate cluster")
86 | if err := createCluster(); err != nil {
87 | return err
88 | }
89 | }
90 | dspin, _ := pterm.DefaultSpinner.
91 | WithDelay(time.Second).
92 | WithRemoveWhenDone(true).
93 | WithShowTimer(true).
94 | WithText("Init()\n").
95 | WithSequence("|", "/", "-", "|", "/", "-", "\\").Start()
96 | dspin.SuccessPrinter.Println("ensuring it's in kubeconfig")
97 | if err := updateKubeconfig(); err != nil {
98 | pterm.Error.Printfln("updateKubeconfig(): %v", err)
99 | }
100 | dspin.UpdateText("setting context")
101 | if err := sh.Run("kubectl", "config", "use-context", constants.KindContextName); err != nil {
102 | dspin.WarningPrinter.Printfln("default context might not be setup correct to new context: %v", err)
103 | }
104 | if err := sh.Run("kubectl", "config", "set-context", "--context", constants.KindContextName, "--current", "--namespace", constants.KubectlNamespace); err != nil {
105 | dspin.WarningPrinter.Printfln("default namespace might not be setup correct to new namespace: %v", err)
106 | }
107 | // Create the namespace if it doesn't exist.
108 | dspin.UpdateText("creating namespace if not exists")
109 | if _, err := sh.Output("kubectl", "get", "namespace", constants.KubectlNamespace); err != nil {
110 | dspin.UpdateText(fmt.Sprintf("namespace does not exist, creating namespace: %s...", constants.KubectlNamespace))
111 |
112 | if err := sh.Run("kubectl", "create", "namespace", constants.KubectlNamespace); err != nil {
113 | dspin.FailPrinter.Printfln("unable to create namespace: %v", err)
114 | return fmt.Errorf("kubectl create namespace %s: %w", constants.KubectlNamespace, err)
115 | }
116 | dspin.SuccessPrinter.Printfln("namespace created: %s", constants.KubectlNamespace)
117 | }
118 | dspin.UpdateText("pulling docker images")
119 | if err := sh.Run("docker", "pull", constants.DockerImageQualified); err != nil {
120 | dspin.WarningPrinter.Printfln("docker pull: %v", err)
121 | return fmt.Errorf("docker pull: %w", err)
122 | }
123 | dspin.SuccessPrinter.Println("docker image for " + constants.DockerImageQualified)
124 | // Not working right now, can't find nodes for Kind to preload. Not critical so commenting out for now - sheldon.
125 | // Sp.UpdateText("preloading docker image into kind cluster")
126 | // if err := sh.Run("kind", "load", "docker-image", "quay.io/delinea/dsv-k8s:latest"); err != nil {
127 | // return fmt.Errorf("kind load docker-image: %w", err)
128 | // }.
129 | dspin.SuccessPrinter.Println("(Kind) Init()")
130 | _ = dspin.Stop()
131 | return nil
132 | }
133 |
134 | // 🗑️ Destroy tears down the Kind cluster.
135 | func (Kind) Destroy() error {
136 | mtu.CheckPtermDebug()
137 | if err := sh.Run("kind", "delete", "cluster", "--name", constants.KindClusterName); err != nil {
138 | pterm.Error.Printfln("kind delete error: %v", err)
139 | return err
140 | }
141 | if err := sh.Run("kubectl", "config", "unset", fmt.Sprintf("clusters.%s", constants.KindContextName)); err != nil {
142 | pterm.Warning.Printfln("default context might not be setup correct to new context: %v", err)
143 | }
144 |
145 | pterm.Success.Println("(Kind) Destroy()")
146 | return nil
147 | }
148 |
--------------------------------------------------------------------------------
/magefiles/mage.go:
--------------------------------------------------------------------------------
1 | //go:build ignore
2 |
3 | // This file lets you run mage with a no-install option as long as you have go.
4 | // To invoke just run go run main.go [task] [parameters]
5 | // To use mage directly, install it, then run mage [task] [parameters]
6 | package main
7 |
8 | import (
9 | "os"
10 |
11 | "github.com/magefile/mage/mage"
12 | )
13 |
14 | func main() { os.Exit(mage.Main()) }
15 |
--------------------------------------------------------------------------------
/magefiles/magefile.go:
--------------------------------------------------------------------------------
1 | // ⚡ Core Mage Tasks.
2 | package main
3 |
4 | import (
5 | "os"
6 | "os/exec"
7 | "runtime"
8 |
9 | "github.com/DelineaXPM/dsv-k8s/v2/magefiles/constants"
10 | "github.com/bitfield/script"
11 |
12 | // mage:import
13 | "github.com/DelineaXPM/dsv-k8s/v2/magefiles/helm"
14 | // mage:import
15 | "github.com/DelineaXPM/dsv-k8s/v2/magefiles/k8s"
16 | // mage:import
17 | _ "github.com/DelineaXPM/dsv-k8s/v2/magefiles/kind"
18 | // mage:import
19 | _ "github.com/DelineaXPM/dsv-k8s/v2/magefiles/minikube"
20 | // mage:import
21 | _ "github.com/DelineaXPM/dsv-k8s/v2/magefiles/vault"
22 | "github.com/magefile/mage/mg"
23 | "github.com/magefile/mage/sh"
24 | "github.com/pterm/pterm"
25 | "github.com/sheldonhull/magetools/ci"
26 | "github.com/sheldonhull/magetools/fancy"
27 | "github.com/sheldonhull/magetools/pkg/magetoolsutils"
28 |
29 | // mage:import
30 | "github.com/sheldonhull/magetools/gotools"
31 | )
32 |
33 | // createDirectories creates the local working directories for build artifacts and tooling.
34 | func createDirectories() error {
35 | for _, dir := range []string{constants.ArtifactDirectory, constants.CacheDirectory, constants.ConfigsDirectory} {
36 | if err := os.MkdirAll(dir, constants.PermissionUserReadWriteExecute); err != nil {
37 | pterm.Error.Printf("failed to create dir: [%s] with error: %v\n", dir, err)
38 |
39 | return err
40 | }
41 | pterm.Success.Printf("✅ [%s] dir created\n", dir)
42 | }
43 |
44 | return nil
45 | }
46 |
47 | // Init runs multiple tasks to initialize all the requirements for running a project for a new contributor.
48 | func Init() error { //nolint:deadcode // Not dead, it's alive.
49 | fancy.IntroScreen(ci.IsCI())
50 | pterm.Success.Println("running Init()...")
51 |
52 | mg.SerialDeps(
53 | Clean,
54 | createDirectories,
55 | (gotools.Go{}.Tidy),
56 | )
57 |
58 | _, err := exec.LookPath("aqua")
59 | if err != nil && os.IsNotExist(err) {
60 | pterm.Error.Printfln("unable to resolve aqua cli tool, please install for automated project tooling setup: https://aquaproj.github.io/docs/tutorial-basics/quick-start#install-aqua")
61 | return err
62 | }
63 |
64 | if ci.IsCI() {
65 | installArgs := []string{}
66 |
67 | if mg.Verbose() {
68 | installArgs = append(installArgs, "--log-level")
69 | installArgs = append(installArgs, "debug")
70 | }
71 | installArgs = append(installArgs, "install")
72 | installArgs = append(installArgs, "aqua")
73 | if err := sh.RunV("aqua", installArgs...); err != nil {
74 | pterm.Error.Printfln("aqua-ci%v", err)
75 | return err
76 | }
77 | pterm.Debug.Println("CI detected, done with init")
78 | return nil
79 | }
80 |
81 | pterm.DefaultSection.Println("Aqua install (any first packages)")
82 | if err := sh.RunV("aqua", "install", "--tags", "first"); err != nil {
83 | pterm.Warning.Printfln("aqua install failed, continuing: %v", err)
84 | }
85 | pterm.Success.Println("aqua install --tags first complete")
86 | pterm.DefaultSection.Println("Aqua install remaining tools")
87 | if err := sh.RunV("aqua", "install"); err != nil {
88 | pterm.Warning.Printfln("aqua install failed, continuing: %v", err)
89 | }
90 | pterm.Success.Println("aqua install complete")
91 | // These can run in parallel as different toolchains.
92 | mg.SerialDeps(
93 | (InstallTrunk),
94 | (TrunkInit),
95 | )
96 | pterm.Info.Printfln("Initializing .cache/ directory with copies of Kubernetes YAML + Helm charts.\nUse this to edit your local configurations for minikube based testing")
97 | mg.Deps(
98 | k8s.K8s{}.Init,
99 | helm.Helm{}.Init,
100 | )
101 | return nil
102 | }
103 |
104 | // InstallTrunk installs trunk.io tooling if it isn't already found.
105 | func InstallTrunk() error {
106 | magetoolsutils.CheckPtermDebug()
107 | pterm.DefaultSection.Println("InstallTrunk()")
108 | if runtime.GOOS == "windows" {
109 | pterm.Warning.Println("InstallTrunk() trunk.io not supported on windows, skipping")
110 | return nil
111 | }
112 | _, err := exec.LookPath("trunk")
113 | if err != nil {
114 | // if os.IsNotExist(err) {
115 | pterm.Warning.Printfln("unable to resolve aqua cli tool, please install for automated project tooling setup: https://aquaproj.github.io/docs/tutorial-basics/quick-start#install-aqua")
116 | _, err := script.Exec("curl https://get.trunk.io -fsSL").Exec("bash -s -- -y").Stdout()
117 | if err != nil {
118 | return err
119 | }
120 | // }
121 | } else {
122 | pterm.Success.Printfln("trunk.io already installed, skipping")
123 | }
124 | return nil
125 | }
126 |
127 | // TrunkInit ensures the required runtimes are installed.
128 | func TrunkInit() error {
129 | return sh.RunV("trunk", "install")
130 | }
131 |
132 | // 🗑️ Clean removes just the artifacts (generated by goreleaser).
133 | func Clean() {
134 | pterm.Success.Println("Cleaning...")
135 | for _, dir := range []string{constants.ArtifactDirectory} {
136 | err := os.RemoveAll(dir)
137 | if err != nil {
138 | pterm.Error.Printf("failed to removeall: [%s] with error: %v\n", dir, err)
139 | }
140 | pterm.Success.Printf("🧹 [%s] dir removed\n", dir)
141 | }
142 | mg.Deps(createDirectories)
143 | }
144 |
145 | // 🗑️ DeepClean removes artifacts, as well as local cached working files and generated credential artifacts.
146 | func DeepClean() {
147 | pterm.Success.Println("Cleaning...")
148 | for _, dir := range []string{constants.ArtifactDirectory, constants.CacheDirectory, constants.ConfigsDirectory} {
149 | err := os.RemoveAll(dir)
150 | if err != nil {
151 | pterm.Error.Printf("failed to removeall: [%s] with error: %v\n", dir, err)
152 | }
153 | pterm.Success.Printf("🧹 [%s] dir removed\n", dir)
154 | }
155 | mg.Deps(createDirectories)
156 | }
157 |
--------------------------------------------------------------------------------
/pkg/config/credentials.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io"
7 | "os"
8 |
9 | "github.com/DelineaXPM/dsv-sdk-go/v2/vault"
10 | )
11 |
12 | // Credentials is a mapping of credentialName to dsv-sdk-go/vault/Configuration objects
13 | type Credentials map[string]struct {
14 | vault.Configuration
15 | }
16 |
17 | // GetCredentials opens the credentialsFile and calls GetCredentialsFromFile on the resulting file
18 | func GetCredentials(credentialsFilePath string) (*Credentials, error) {
19 | if credentialsFile, err := os.Open(credentialsFilePath); err != nil {
20 | return nil, fmt.Errorf("unable to open configuration file '%s': %w", credentialsFilePath, err)
21 | } else {
22 | defer credentialsFile.Close()
23 | return GetCredentialsFromFile(credentialsFile)
24 | }
25 | }
26 |
27 | // GetCredentialsFromFile parses the credentialsFile and returns the resulting Credentials object
28 | func GetCredentialsFromFile(credentialsFile *os.File) (*Credentials, error) {
29 | if contents, err := io.ReadAll(credentialsFile); err != nil {
30 | return nil, fmt.Errorf("unable to read configuration file '%s': %w", credentialsFile.Name(), err)
31 | } else {
32 | return MakeCredentials(contents)
33 | }
34 | }
35 |
36 | func MakeCredentials(credentialJSON []byte) (*Credentials, error) {
37 | credentials := new(Credentials)
38 |
39 | if err := json.Unmarshal(credentialJSON, credentials); err != nil {
40 | return nil, fmt.Errorf("unable to unmarshal configuration: %w", err)
41 | } else {
42 | return credentials, nil
43 | }
44 | }
45 |
46 | // Names returns the list of credential names
47 | func (credentials Credentials) Names() []string {
48 | names := make([]string, 0, len(credentials))
49 |
50 | for name := range credentials {
51 | names = append(names, name)
52 | }
53 | return names
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/config/credentials_test.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "io"
5 | "log"
6 | "testing"
7 | )
8 |
9 | // Ensure log output doesn't pollute tests.
10 | func TestMain(m *testing.M) {
11 | log.SetOutput(io.Discard)
12 | }
13 |
14 | func TestMakeCredentialsValid(t *testing.T) {
15 | if _, err := MakeCredentials([]byte(`
16 | {
17 | "a": {
18 | "credentials": {
19 | "clientId": "x",
20 | "clientSecret": "y"
21 | },
22 | "tenant": "i"
23 | },
24 | "b": {
25 | "credentials": {
26 | "clientId": "x",
27 | "clientSecret": "y"
28 | },
29 | "tenant": "j"
30 | }
31 | }`)); err != nil {
32 | t.Errorf("MakeCredentials should not have failed")
33 | }
34 | }
35 |
36 | func TestMakeCredentialsInvalid(t *testing.T) {
37 | if _, err := MakeCredentials([]byte(`
38 | {
39 | "a": {
40 | "credentials": {
41 | "clientId": "x",
42 | },
43 | "tenant": "i"
44 | }
45 | }`)); err == nil {
46 | t.Errorf("MakeCredentials should have failed")
47 | }
48 | }
49 |
50 | func TestCredentials(t *testing.T) {
51 | if credentials, err := MakeCredentials([]byte(`
52 | {
53 | "a": {
54 | "credentials": {
55 | "clientId": "x",
56 | "clientSecret": "y"
57 | },
58 | "tenant": "i"
59 | },
60 | "b": {
61 | "credentials": {
62 | "clientId": "x",
63 | "clientSecret": "y"
64 | },
65 | "tenant": "j"
66 | },
67 | "c": {
68 | "credentials": {
69 | "clientId": "x",
70 | "clientSecret": "y"
71 | },
72 | "tenant": "k"
73 | }
74 | }
75 | `)); err != nil {
76 | t.Error(err)
77 | } else {
78 | if len(*credentials) != 3 {
79 | t.Errorf("expected 3 credential, got %d", len(*credentials))
80 | }
81 | if names := credentials.Names(); len(names) != 3 {
82 | t.Errorf("expected 3 name, got %d", len(names))
83 | } else {
84 | switch names[0] {
85 | case "a":
86 | case "b":
87 | case "c":
88 | break
89 | default:
90 | t.Errorf("unexpected name '%s'", names[0])
91 | }
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/pkg/injector/inject.go:
--------------------------------------------------------------------------------
1 | package injector
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/DelineaXPM/dsv-k8s/v2/pkg/config"
7 | patch "github.com/DelineaXPM/dsv-k8s/v2/pkg/patch"
8 | "github.com/rs/zerolog"
9 | v1 "k8s.io/api/admission/v1"
10 | corev1 "k8s.io/api/core/v1"
11 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 | "k8s.io/apimachinery/pkg/types"
13 | )
14 |
15 | // Inject adds to, updates or replaces the k8s Secret.Data with dsv Secret.Data (see above)
16 | func Inject(secret corev1.Secret, uID types.UID, credentials config.Credentials, log zerolog.Logger) (*v1.AdmissionResponse, error) {
17 | if jsonPatch, err := patch.GenerateJsonPatch(secret, credentials); err != nil {
18 | log.Error().Err(err).
19 | Str("secret_name", secret.Name).
20 | Str("namespace", secret.Namespace).
21 | Msg("unable to patch secret")
22 | return nil, fmt.Errorf("unable to generate JSON patch for Secret '%s': %w", secret.Name, err)
23 | } else if jsonPatch != nil {
24 | patchType := v1.PatchTypeJSONPatch
25 |
26 | log.Debug().Str("secret_name", secret.Name).Msg("patching secret")
27 | return &v1.AdmissionResponse{
28 | Allowed: true,
29 | Result: &metav1.Status{
30 | Status: metav1.StatusSuccess,
31 | },
32 | UID: uID,
33 | PatchType: &patchType,
34 | Patch: jsonPatch,
35 | }, nil
36 | } else {
37 | log.Debug().Str("secret_name", secret.Name).Msg("no patching required")
38 | return &v1.AdmissionResponse{
39 | Allowed: true,
40 | Result: &metav1.Status{
41 | Status: metav1.StatusSuccess,
42 | },
43 | UID: uID,
44 | }, nil
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/patch/patch.go:
--------------------------------------------------------------------------------
1 | package patch
2 |
3 | import (
4 | "encoding/base64"
5 | "encoding/json"
6 | "fmt"
7 | "strings"
8 | "time"
9 |
10 | "github.com/DelineaXPM/dsv-k8s/v2/pkg/config"
11 | "github.com/DelineaXPM/dsv-sdk-go/v2/vault"
12 | "github.com/mattbaird/jsonpatch"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | /*
17 | credentialsAnnotation contains a name that maps to a set of credentials in Credentials (see below)
18 | setAnnotation, addAnnoation and updateAnnotation contain the path to the DSV Secret
19 | that will be used to modified this Secret.
20 | addAnnotation adds missing fields without overwriting or removing existing fields
21 | updateAnnotation adds and overwrites existing fields but does not remove fields
22 | setAnnotation overwrites fields and removes fields that do not exist in the DSV Secret
23 | */
24 | const (
25 | credentialsAnnotation = "dsv.delinea.com/credentials"
26 | setAnnotation = "dsv.delinea.com/set-secret"
27 | addAnnotation = "dsv.delinea.com/add-to-secret"
28 | updateAnnotation = "dsv.delinea.com/update-secret"
29 | tsAnnotation = "dsv.delinea.com/modified"
30 | versionAnnotation = "dsv.delinea.com/version"
31 | )
32 |
33 | /*
34 | noPatch causes Inject to approve without patching
35 | patchAdd causes Inject to add entries without overwriting or removing existing ones
36 | patchUpdate causes Inject to add and update entries without removing existing ones
37 | patchOverwrite causes Inject to completely overwrite all entries including removal
38 | of existing entries that are not present in the DSV Secret
39 | */
40 | const (
41 | noPatch = iota
42 | patchAdd
43 | patchUpdate
44 | patchOverwrite
45 | )
46 |
47 | // GeneratePatch generates a JSON Patch that applies changes to the k8s Secret based on the DSV Secret that it refers to
48 | func GenerateJsonPatch(secret v1.Secret, credentials config.Credentials) ([]byte, error) {
49 | if patchOperations, err := makePatchOperations(secret, credentials); err != nil {
50 | return nil, err
51 | } else if patchOperations != nil {
52 | if jsonPatch, err := json.Marshal(patchOperations); err != nil {
53 | return nil, fmt.Errorf("unable to marshal JsonPatch: %s", err)
54 | } else {
55 | return jsonPatch, nil
56 | }
57 | } else {
58 | return nil, nil
59 | }
60 | }
61 |
62 | func makePatchOperations(secret v1.Secret, credentials config.Credentials) ([]jsonpatch.JsonPatchOperation, error) {
63 | annotations := secret.ObjectMeta.Annotations
64 | patchMode := noPatch
65 | var secretPath string
66 | var ok bool
67 |
68 | if secretPath, ok = annotations[setAnnotation]; ok {
69 | patchMode = patchOverwrite
70 | } else if secretPath, ok = annotations[addAnnotation]; ok {
71 | patchMode = patchAdd
72 | } else if secretPath, ok = annotations[updateAnnotation]; ok {
73 | patchMode = patchUpdate
74 | }
75 |
76 | if patchMode == noPatch {
77 | return nil, nil
78 | }
79 |
80 | var config vault.Configuration
81 | /*
82 | If there is a credentials annotation, use the credentials by that name
83 | and return an error if there are no credentials for that name.
84 | Otherwise, use the default credentials or, finally,
85 | do nothing if there aren't any.
86 | */
87 | if name, ok := annotations[credentialsAnnotation]; ok {
88 | if credentials, ok := credentials[name]; ok {
89 | config = credentials.Configuration
90 | } else {
91 | return nil, fmt.Errorf("no credentials for: %s", name)
92 | }
93 | } else if credentials, ok := credentials["default"]; ok {
94 | config = credentials.Configuration
95 | } else {
96 | return nil, nil
97 | }
98 |
99 | var vaultSecret *vault.Secret
100 |
101 | /*
102 | If there's a patch annotation, and a credentials annotation that matches
103 | a set of credentials, use them to get a Vault Secret.
104 | */
105 | if vault, err := vault.New(config); err != nil {
106 | return nil, fmt.Errorf("configuration error: %s", err)
107 | } else if vaultSecret, err = vault.Secret(secretPath); err != nil {
108 | return nil, fmt.Errorf("unable to get the secret: %s", err)
109 | }
110 | /*
111 | Use the version annotation to determine if the secret has been modified
112 | */
113 | if vaultSecret.Version == annotations[versionAnnotation] {
114 | return nil, nil
115 | }
116 | /*
117 | CreatePatch returns the difference between the JSON representation of
118 | the DSV Secret Data and the k8s Secret Data, as an RFC 6902 JSON Patch.
119 | */
120 | vsdj, _ := json.Marshal(vaultSecret.Data)
121 | sdj, _ := json.Marshal(secret.Data)
122 | diff, _ := jsonpatch.CreatePatch(sdj, vsdj)
123 | ops := []jsonpatch.JsonPatchOperation{}
124 | /*
125 | Each patch operation has to be updated so that k8s can apply it to
126 | the entire Secret:
127 | 1) the Path must be relative to /Secret rather than /Secret/Data
128 | 2) the Values must be Base64 encoded
129 | 3) the Operations that conflict with patchMode must be removed
130 | */
131 | for _, op := range diff {
132 | op.Path = "/data" + op.Path
133 |
134 | switch v := op.Value.(type) {
135 | case []byte:
136 | op.Value = base64.StdEncoding.EncodeToString(v)
137 | case string:
138 | op.Value = base64.StdEncoding.EncodeToString([]byte(v))
139 | case map[string]interface{}:
140 | if json, err := json.Marshal(v); err != nil {
141 | return nil, fmt.Errorf("unable to marshal value for %s operation on %s: %s",
142 | op.Operation, op.Path, err)
143 | } else {
144 | op.Value = base64.StdEncoding.EncodeToString([]byte(json))
145 | }
146 | }
147 | // remove operations that conflict with the patchMode
148 | switch op.Operation {
149 | case "replace":
150 | if patchMode == patchAdd {
151 | continue
152 | }
153 | case "remove":
154 | if patchMode == patchAdd || patchMode == patchUpdate {
155 | continue
156 | }
157 | }
158 | ops = append(ops, op)
159 | }
160 | /*
161 | If there is at least one patch operation add an operation to replace update the annotations
162 | */
163 | if len(ops) > 0 {
164 | operation := "add"
165 | if annotations[versionAnnotation] != "" {
166 | operation = "replace"
167 | }
168 | annotation_ops := []jsonpatch.JsonPatchOperation{
169 | {
170 | Operation: operation,
171 | Path: "/metadata/annotations/" + strings.Replace(tsAnnotation, "/", "~1", -1),
172 | Value: time.Now().UTC().Format(time.UnixDate),
173 | },
174 | {
175 | Operation: operation,
176 | Path: "/metadata/annotations/" + strings.Replace(versionAnnotation, "/", "~1", -1),
177 | Value: vaultSecret.Version,
178 | },
179 | }
180 | ops = append(ops, annotation_ops...)
181 | return ops, nil
182 | }
183 | return nil, nil
184 | }
185 |
--------------------------------------------------------------------------------
/pkg/syncer/sync.go:
--------------------------------------------------------------------------------
1 | // package syncer handles the syncing actions for secret reading, patching and injecting into kubernetes secrets.
2 | package syncer
3 |
4 | import (
5 | "context"
6 | "fmt"
7 | "sync"
8 | "time"
9 |
10 | "github.com/rs/zerolog"
11 |
12 | "github.com/DelineaXPM/dsv-k8s/v2/internal/k8s"
13 | "github.com/DelineaXPM/dsv-k8s/v2/pkg/config"
14 | "github.com/DelineaXPM/dsv-k8s/v2/pkg/patch"
15 | corev1 "k8s.io/api/core/v1"
16 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17 | "k8s.io/apimachinery/pkg/types"
18 | )
19 |
20 | // Sync does the same thing as Inject, but by iterating over the existing k8s Secrets
21 | func Sync(config k8s.Config, namespace string, credentials config.Credentials, log zerolog.Logger) error {
22 | secretsClient, err := k8s.GetSecretsClient(config, namespace)
23 | if err != nil {
24 | return fmt.Errorf("[ERROR] error getting a Kubernetes Client API Secrets Client: %w", err)
25 | }
26 | log.Debug().Str("namespace", namespace).Msg("getting a list of secrets")
27 |
28 | if secrets, err := secretsClient.List(context.TODO(), metav1.ListOptions{}); err != nil {
29 | return fmt.Errorf("[ERROR] unable to get a list of secrets in namespace %q: %w", namespace, err)
30 | } else {
31 | wg := sync.WaitGroup{}
32 |
33 | log.Info().Msgf("processing %d Secrets", len(secrets.Items))
34 | for _, secret := range secrets.Items {
35 | log.Debug().Msgf("processing k8s Secret %q", secret.Name)
36 | wg.Add(1)
37 | go pp(secret, credentials, config, &wg, log)
38 | } // TODO: put an upper limit on the number of goroutines to spawn in one go
39 | wg.Wait()
40 | if secrets.RemainingItemCount != nil && *secrets.RemainingItemCount > 0 {
41 | log.Warn().Msgf("this server pages; %d Secrets were not processed", secrets.RemainingItemCount)
42 | }
43 | }
44 | return nil
45 | }
46 |
47 | // pp possibly patches the Kubernetes Secret
48 | func pp(secret corev1.Secret, credentials config.Credentials, config k8s.Config, wg *sync.WaitGroup, log zerolog.Logger) {
49 | defer wg.Done()
50 | start := time.Now()
51 | defer func() {
52 | log.Debug().
53 | Dur("duration", time.Since(start)).
54 | Str("secret_name", secret.Name).
55 | Bool("patched", true).
56 | Msg("possible patch complete")
57 | }()
58 |
59 | if jsonPatch, err := patch.GenerateJsonPatch(secret, credentials); err != nil { //nolint:nestif // known issue, but will would be refactoring for the future
60 | log.Error().
61 | Err(err).
62 | Str("secret_name", secret.Name).
63 | Str("secret_namespace", secret.Namespace).
64 | Bool("patched", false).
65 | Msg("patch.GenerateJsonPatch")
66 | } else if jsonPatch == nil {
67 | log.Debug().
68 | Str("secret_name", secret.Name).
69 | Str("secret_namespace", secret.Namespace).
70 | Bool("patched", false).
71 | Msg("GenerateJsonPatch")
72 | } else {
73 | if secretsClient, err := k8s.GetSecretsClient(config, secret.Namespace); err != nil {
74 | log.Error().
75 | Err(err).
76 | Str("secret_name", secret.Name).
77 | Str("secret_namespace", secret.Namespace).
78 | Bool("patched", false).
79 | Msg("k8s.GetSecretsClient")
80 | } else {
81 | if _, err := secretsClient.Patch(
82 | context.TODO(), secret.Name, types.JSONPatchType, jsonPatch, metav1.PatchOptions{},
83 | ); err != nil {
84 | log.Error().
85 | Err(err).
86 | Str("secret_name", secret.Name).
87 | Str("secret_namespace", secret.Namespace).
88 | Bool("patched", true).
89 | Msg("secretsClient.Patch")
90 | } else {
91 | log.Info().
92 | Str("secret_name", secret.Name).
93 | Str("secret_namespace", secret.Namespace).
94 | Bool("patched", true).
95 | Msg("patch successful")
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": ["DelineaXPM/renovate-config:security"],
4 | "packageRules": [
5 | {
6 | "matchManagers": ["gomod"],
7 | "matchPackageNames": [
8 | "helm.sh/helm/v3",
9 | "github.com/mittwald/go-helm-client"
10 | ],
11 | "groupName": "risky-breaking-changes",
12 | "enabled": false
13 | },
14 | {
15 | "matchManagers": ["gomod"],
16 | "matchPackageNames": ["k8s.io/api"],
17 | "groupName": "risky-k8s-changes",
18 | "matchUpdateTypes": ["major", "minor"],
19 | "enabled": false
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------