├── LICENSE ├── Makefile ├── README.md └── kubectl-gopass /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Martin Hoefling 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY release: 2 | git diff-index --quiet HEAD -- 3 | git tag v$$(./kubectl-gopass version) 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kubectl-gopass 2 | 3 | A [plugin for kubectl](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/) to support reading and writing secrets directly from/to [gopass](https://github.com/gopasspw/gopass). 4 | 5 | ## Installation: 6 | 7 | Currently, you need to download the shell script, put it in your path and make it executable. 8 | It's also available via [krew](https://github.com/kubernetes-sigs/krew). 9 | 10 | Gopass and kubectl is required for all functionality, jq and yq are required for fetching secrets from kubernetes to gopass. 11 | 12 | ## Usage: 13 | 14 | # kubectl gopass apply [optional kubectl apply params] my-secret 15 | applies secret "my-secret" via kubectl. Namespace and other params can be 16 | specified and are passed through to kubectl. 17 | 18 | # kubectl gopass apply-recursive [optional kubectl apply params] my-secret-path 19 | 20 | like apply but takes a path and applies all secrets below that path 21 | 22 | # kubectl gopass diff [optional kubectl apply params] my-secret 23 | shows the secret diff of "my-secret" via kubectl. Namespace and other 24 | params can be specified and are passed through to kubectl. 25 | 26 | # kubectl gopass diff-recursive [optional kubectl apply params] my-secret-path 27 | 28 | like diff but takes a path and applies all secrets below that path 29 | 30 | # kubectl gopass create my-new-secret 31 | create a new secret prefilled with a kubernetes secret template and starts 32 | an editor to edit the newly created secret 33 | 34 | # kubectl gopass fetch [optional kubectl get secret params] secret-name dir/to/gopass-secret 35 | fetches a secret with name from the kubernetes cluster and stores in in gopass as dir/to/gopass-secret 36 | 37 | # kubectl gopass fetchrecursive [optional kubectl get secret params] dir/to/gopass-secret-path 38 | fetches all secrets from the kubernetes cluster (namespace) and stores them in gopass dir/to/gopass-secret-path 39 | 40 | # kubectl gopass version 41 | prints out the kubectl-gopass version ($VERSION) 42 | 43 | # kubectl gopass help 44 | prints these usage instructions 45 | 46 | 47 | ## Contributions 48 | 49 | are welcome :-) 50 | -------------------------------------------------------------------------------- /kubectl-gopass: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | VERSION='0.1.0' 4 | 5 | set -euo pipefail 6 | 7 | function usage() { 8 | cat <&2 "Too few arguments, secret is required" 50 | usage 51 | exit 1 52 | fi 53 | SECRET="${*: -1}" 54 | 55 | KUBECTL_ARGS=("$@") 56 | unset "KUBECTL_ARGS[${#KUBECTL_ARGS[@]}-1]" 57 | unset "KUBECTL_ARGS[0]" 58 | LEN_KUBECTL_ARGS=${#KUBECTL_ARGS[@]} 59 | if [[ "$LEN_KUBECTL_ARGS" -lt 1 ]]; then 60 | echo "will $1 secret $SECRET" 61 | else 62 | echo "will $1 secret $SECRET with additional kubectl args '" "${KUBECTL_ARGS[@]}" "'" 63 | fi 64 | $GOPASS show "$SECRET" | $KUBECTL "$1" ${KUBECTL_ARGS[@]+"${KUBECTL_ARGS[@]}"} -f - 65 | } 66 | 67 | recursive() { 68 | if [[ "$#" -lt 2 ]]; then 69 | echo >&2 "Too few arguments, secret path is required" 70 | usage 71 | exit 1 72 | fi 73 | 74 | SECRETPATH="${*: -1}" 75 | 76 | KUBECTL_ARGS=("$@") 77 | unset "KUBECTL_ARGS[${#KUBECTL_ARGS[@]}-1]" 78 | unset "KUBECTL_ARGS[0]" 79 | 80 | IFS=$'\n' 81 | for SECRET in $(gopass ls -f "$SECRETPATH"); do 82 | diff_or_apply "$1" ${KUBECTL_ARGS[@]+"${KUBECTL_ARGS[@]}"} "$SECRET" || true 83 | done 84 | } 85 | 86 | create() { 87 | if [[ "$#" -lt 1 ]]; then 88 | echo >&2 "Too few arguments, target secret is required" 89 | usage 90 | exit 1 91 | fi 92 | SECRETNAME=${*:(-1)} 93 | 94 | gopass insert "$SECRETNAME" <&2 "Too few arguments, kubernetes secret and target gopass secret is required" 111 | usage 112 | exit 1 113 | fi 114 | SECRET="${*: (-2):1}" 115 | TARGET="${*: -1}" 116 | 117 | KUBECTL_ARGS=("$@") 118 | unset "KUBECTL_ARGS[${#KUBECTL_ARGS[@]}-1]" 119 | unset "KUBECTL_ARGS[0]" 120 | LEN_KUBECTL_ARGS=${#KUBECTL_ARGS[@]} 121 | if [[ "$LEN_KUBECTL_ARGS" -lt 1 ]]; then 122 | echo "will fetch secret $SECRET" 123 | else 124 | echo "will fetch secret $SECRET with additional kubectl args '" "${KUBECTL_ARGS[@]}" "'" 125 | fi 126 | $KUBECTL get secret ${KUBECTL_ARGS[@]+"${KUBECTL_ARGS[@]}"} $SECRET -o json | \ 127 | $JQ 'del(.metadata.creationTimestamp)|del(.metadata.resourceVersion)|del(.metadata.selfLink)|del(.metadata.uid)|.data[] |= @base64d | . + {"stringData": .data} | del(.data)' | \ 128 | $YQ read - | \ 129 | $GOPASS insert "${TARGET}" 130 | } 131 | 132 | fetchrecursive() { 133 | if [[ "$#" -lt 2 ]]; then 134 | echo >&2 "Too few arguments, target gopass path is required" 135 | usage 136 | exit 1 137 | fi 138 | TARGET="${*: -1}" 139 | 140 | KUBECTL_ARGS=("$@") 141 | unset "KUBECTL_ARGS[${#KUBECTL_ARGS[@]}-1]" 142 | unset "KUBECTL_ARGS[0]" 143 | LEN_KUBECTL_ARGS=${#KUBECTL_ARGS[@]} 144 | if [[ "$LEN_KUBECTL_ARGS" -lt 1 ]]; then 145 | echo "will fetch secrets to $TARGET" 146 | else 147 | echo "will fetch secrets to $TARGET with additional kubectl args '" "${KUBECTL_ARGS[@]}" "'" 148 | fi 149 | 150 | for SECRET in $($KUBECTL get secrets -o json | $JQ -r ".items[].metadata.name"); do 151 | echo "fetching ${SECRET}" 152 | $KUBECTL get secret ${KUBECTL_ARGS[@]+"${KUBECTL_ARGS[@]}"} $SECRET -o json | \ 153 | $JQ 'del(.metadata.creationTimestamp)|del(.metadata.resourceVersion)|del(.metadata.selfLink)|del(.metadata.uid)|.data[] |= @base64d | . + {"stringData": .data} | del(.data)' | \ 154 | $YQ read - | \ 155 | $GOPASS insert "${TARGET}/${SECRET}" 156 | done 157 | } 158 | 159 | main() { 160 | if hash kubectl 2>/dev/null; then 161 | KUBECTL=kubectl 162 | elif hash kubectl.exe 2>/dev/null; then 163 | KUBECTL=kubectl.exe 164 | else 165 | echo >&2 "kubectl is not installed" 166 | exit 1 167 | fi 168 | 169 | if hash gopass 2>/dev/null; then 170 | GOPASS=gopass 171 | elif hash gopass.exe 2>/dev/null; then 172 | GOPASS=gopass.exe 173 | else 174 | echo >&2 "gopass is not installed" 175 | exit 1 176 | fi 177 | 178 | if hash jq 2>/dev/null; then 179 | JQ=jq 180 | else 181 | echo >&2 "jq is not installed, fetching secrets from kubernetes to gopass will not work" 182 | fi 183 | 184 | if hash yq 2>/dev/null; then 185 | YQ=yq 186 | else 187 | echo >&2 "yq is not installed, fetching secrets from kubernetes to gopass will not work" 188 | fi 189 | 190 | if [[ "$#" -eq 0 ]]; then 191 | usage | less 192 | return 193 | fi 194 | 195 | case "$1" in 196 | '-h' | '--help' | 'help') 197 | usage | less 198 | ;; 199 | 'apply'|'diff') 200 | diff_or_apply "${@:1}" 201 | exit 0 202 | ;; 203 | 'diff-recursive'| 'recursive-diff') 204 | recursive "diff" "${@:2}" 205 | ;; 206 | 'apply-recursive'| 'recursive-apply') 207 | recursive "apply" "${@:2}" 208 | ;; 209 | 'create') 210 | create "${@:1}" 211 | ;; 212 | 'fetch') 213 | fetch "${@:1}" 214 | ;; 215 | 'fetch-recursive') 216 | fetchrecursive "${@:1}" 217 | ;; 218 | 'version') 219 | echo "$VERSION" 220 | exit 0 221 | ;; 222 | -*) 223 | usage 224 | error "unrecognized flag \"${1}\"" 225 | ;; 226 | *) 227 | usage 228 | error "unknown command \"$1\"" 229 | esac 230 | 231 | } 232 | 233 | main "$@" 234 | --------------------------------------------------------------------------------