commit 8fccf09753663fd83e07c01de38d3ca67d9a08d1 Author: uday.ruddarraju Date: Mon Sep 14 10:11:30 2020 -0700 Adding encrypt and decrypt subcommands to secret command Design document: https://docs.google.com/document/d/1EjiCuXoiy8DEEXe15KxVJ4iWrwogCyG113_0LdzcWzQ/edit?usp=drive_web&ouid=102644738301620637153 This is the third of multiple patchsets to support encryption and decryption in airshipctl Complete feature: https://review.opendev.org/#/c/742695/ Change-Id: Ibe1060a83d11233cccaa3d3989765968a4dbed76 diff --git a/cmd/root.go b/cmd/root.go index 145a01b..8144b1a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -78,7 +78,7 @@ func AddDefaultAirshipCTLCommands(cmd *cobra.Command, factory cfg.Factory) *cobr cmd.AddCommand(document.NewDocumentCommand(factory)) cmd.AddCommand(config.NewConfigCommand(factory)) cmd.AddCommand(image.NewImageCommand(factory)) - cmd.AddCommand(secret.NewSecretCommand()) + cmd.AddCommand(secret.NewSecretCommand(factory)) cmd.AddCommand(phase.NewPhaseCommand(factory)) cmd.AddCommand(NewVersionCommand()) diff --git a/cmd/secret/decrypt/decrypt.go b/cmd/secret/decrypt/decrypt.go new file mode 100644 index 0000000..c3e8a79 --- /dev/null +++ b/cmd/secret/decrypt/decrypt.go @@ -0,0 +1,65 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package decrypt + +import ( + "github.com/spf13/cobra" + + "opendev.org/airship/airshipctl/pkg/config" + "opendev.org/airship/airshipctl/pkg/errors" + "opendev.org/airship/airshipctl/pkg/log" +) + +const ( + decryptShort = ` +Decrypt encrypted yaml files into plaintext files representing Kubernetes objects consisting of sensitive data.` + + decryptExample = ` +# Decrypt all encrypted files in the manifests directory. +airshipctl secret decrypt + +# Decrypt encrypted file from src and write the plain text to a different dst file +airshipctl secret decrypt \ + --src /tmp/manifests/target/secrets/encrypted-qualified-secret.yaml \ + --dst /tmp/manifests/target/secrets/qualified-secret.yaml +` +) + +// NewDecryptCommand creates a new command for decrypting encrypted secrets in the manifests +func NewDecryptCommand(_ config.Factory) *cobra.Command { + var srcPath, dstPath string + + decryptCmd := &cobra.Command{ + Use: "decrypt", + Short: decryptShort[1:], + Example: decryptExample, + RunE: func(cmd *cobra.Command, args []string) error { + // TODO: Need to integrate with business logic to decrypt with sops + return errors.ErrNotImplemented{What: "secret encryption/decryption"} + }, + } + decryptCmd.Flags().StringVar(&srcPath, "src", "", + `Path to the file or directory that has secrets in encrypted text that need to be decrypted. `+ + `Defaults to the manifest location in airship config`) + decryptCmd.Flags().StringVar(&dstPath, "dst", "", + "Path to the file or directory to store decrypted secrets. Defaults to src if empty.") + + err := decryptCmd.MarkFlagRequired("dst") + if err != nil { + log.Fatalf("marking dst flag required failed: %v", err) + } + + return decryptCmd +} diff --git a/cmd/secret/decrypt/decrypt_test.go b/cmd/secret/decrypt/decrypt_test.go new file mode 100644 index 0000000..d669467 --- /dev/null +++ b/cmd/secret/decrypt/decrypt_test.go @@ -0,0 +1,36 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package decrypt_test + +import ( + "testing" + + "opendev.org/airship/airshipctl/cmd/secret/decrypt" + "opendev.org/airship/airshipctl/testutil" +) + +func TestDecrypt(t *testing.T) { + cmdTests := []*testutil.CmdTest{ + { + Name: "decrypt-cmd-cmd-with-help", + CmdLine: "--help", + Cmd: decrypt.NewDecryptCommand(nil), + }, + } + + for _, tt := range cmdTests { + testutil.RunTest(t, tt) + } +} diff --git a/cmd/secret/decrypt/testdata/TestDecryptGoldenOutput/decrypt-cmd-cmd-with-help.golden b/cmd/secret/decrypt/testdata/TestDecryptGoldenOutput/decrypt-cmd-cmd-with-help.golden new file mode 100644 index 0000000..1197943 --- /dev/null +++ b/cmd/secret/decrypt/testdata/TestDecryptGoldenOutput/decrypt-cmd-cmd-with-help.golden @@ -0,0 +1,20 @@ +Decrypt encrypted yaml files into plaintext files representing Kubernetes objects consisting of sensitive data. + +Usage: + decrypt [flags] + +Examples: + +# Decrypt all encrypted files in the manifests directory. +airshipctl secret decrypt + +# Decrypt encrypted file from src and write the plain text to a different dst file +airshipctl secret decrypt \ + --src /tmp/manifests/target/secrets/encrypted-qualified-secret.yaml \ + --dst /tmp/manifests/target/secrets/qualified-secret.yaml + + +Flags: + --dst string Path to the file or directory to store decrypted secrets. Defaults to src if empty. + -h, --help help for decrypt + --src string Path to the file or directory that has secrets in encrypted text that need to be decrypted. Defaults to the manifest location in airship config diff --git a/cmd/secret/encrypt/encrypt.go b/cmd/secret/encrypt/encrypt.go new file mode 100644 index 0000000..2fa7972 --- /dev/null +++ b/cmd/secret/encrypt/encrypt.go @@ -0,0 +1,64 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package encrypt + +import ( + "github.com/spf13/cobra" + + "opendev.org/airship/airshipctl/pkg/config" + "opendev.org/airship/airshipctl/pkg/errors" + "opendev.org/airship/airshipctl/pkg/log" +) + +const ( + encryptShort = ` +Encrypt plain text yaml files representing Kubernetes objects consisting of sensitive configuration.` + + encryptExample = ` +# Encrypt all kubernetes objects in the manifests directory. +airshipctl secret encrypt + +# Encrypt file from src and write to a different dst file +airshipctl secret encrypt \ + --src /tmp/manifests/target/secrets/qualified-secret.yaml \ + --dst /tmp/manifests/target/secrets/encrypted-qualified-secret.yaml +` +) + +// NewEncryptCommand creates a new command for encrypting plain text secrets using sops +func NewEncryptCommand(_ config.Factory) *cobra.Command { + var srcPath, dstPath string + + encryptCmd := &cobra.Command{ + Use: "encrypt", + Short: encryptShort[1:], + Example: encryptExample, + RunE: func(cmd *cobra.Command, args []string) error { + return errors.ErrNotImplemented{What: "secret encryption/decryption"} + }, + } + encryptCmd.Flags().StringVar(&srcPath, "src", "", + `Path to the file or directory that has secrets in plaintext that need to be encrypted. `+ + `Defaults to the manifest location in airship config`) + encryptCmd.Flags().StringVar(&dstPath, "dst", "", + "Path to the file or directory that has encrypted secrets for decryption. Defaults to src if empty.") + + err := encryptCmd.MarkFlagRequired("dst") + if err != nil { + log.Fatalf("marking dst flag required failed: %v", err) + } + + return encryptCmd +} diff --git a/cmd/secret/encrypt/encrypt_test.go b/cmd/secret/encrypt/encrypt_test.go new file mode 100644 index 0000000..88a6a6a --- /dev/null +++ b/cmd/secret/encrypt/encrypt_test.go @@ -0,0 +1,36 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package encrypt_test + +import ( + "testing" + + "opendev.org/airship/airshipctl/cmd/secret/encrypt" + "opendev.org/airship/airshipctl/testutil" +) + +func TestDecrypt(t *testing.T) { + cmdTests := []*testutil.CmdTest{ + { + Name: "encrypt-cmd-cmd-with-help", + CmdLine: "--help", + Cmd: encrypt.NewEncryptCommand(nil), + }, + } + + for _, tt := range cmdTests { + testutil.RunTest(t, tt) + } +} diff --git a/cmd/secret/encrypt/testdata/TestDecryptGoldenOutput/encrypt-cmd-cmd-with-help.golden b/cmd/secret/encrypt/testdata/TestDecryptGoldenOutput/encrypt-cmd-cmd-with-help.golden new file mode 100644 index 0000000..e63f1fc --- /dev/null +++ b/cmd/secret/encrypt/testdata/TestDecryptGoldenOutput/encrypt-cmd-cmd-with-help.golden @@ -0,0 +1,20 @@ +Encrypt plain text yaml files representing Kubernetes objects consisting of sensitive configuration. + +Usage: + encrypt [flags] + +Examples: + +# Encrypt all kubernetes objects in the manifests directory. +airshipctl secret encrypt + +# Encrypt file from src and write to a different dst file +airshipctl secret encrypt \ + --src /tmp/manifests/target/secrets/qualified-secret.yaml \ + --dst /tmp/manifests/target/secrets/encrypted-qualified-secret.yaml + + +Flags: + --dst string Path to the file or directory that has encrypted secrets for decryption. Defaults to src if empty. + -h, --help help for encrypt + --src string Path to the file or directory that has secrets in plaintext that need to be encrypted. Defaults to the manifest location in airship config diff --git a/cmd/secret/secret.go b/cmd/secret/secret.go index 967763c..b68ce6f 100644 --- a/cmd/secret/secret.go +++ b/cmd/secret/secret.go @@ -17,11 +17,14 @@ package secret import ( "github.com/spf13/cobra" + "opendev.org/airship/airshipctl/cmd/secret/decrypt" + "opendev.org/airship/airshipctl/cmd/secret/encrypt" "opendev.org/airship/airshipctl/cmd/secret/generate" + "opendev.org/airship/airshipctl/pkg/config" ) // NewSecretCommand creates a new command for managing airshipctl secrets -func NewSecretCommand() *cobra.Command { +func NewSecretCommand(cfgFactory config.Factory) *cobra.Command { secretRootCmd := &cobra.Command{ Use: "secret", // TODO(howell): Make this more expressive @@ -29,6 +32,8 @@ func NewSecretCommand() *cobra.Command { } secretRootCmd.AddCommand(generate.NewGenerateCommand()) + secretRootCmd.AddCommand(encrypt.NewEncryptCommand(cfgFactory)) + secretRootCmd.AddCommand(decrypt.NewDecryptCommand(cfgFactory)) return secretRootCmd } diff --git a/docs/source/cli/airshipctl_secret.md b/docs/source/cli/airshipctl_secret.md index 02812df..165fe4c 100644 --- a/docs/source/cli/airshipctl_secret.md +++ b/docs/source/cli/airshipctl_secret.md @@ -23,5 +23,7 @@ Manage secrets ### SEE ALSO * [airshipctl](airshipctl.md) - A unified entrypoint to various airship components +* [airshipctl secret decrypt](airshipctl_secret_decrypt.md) - Decrypt encrypted yaml files into plaintext files representing Kubernetes objects consisting of sensitive data. +* [airshipctl secret encrypt](airshipctl_secret_encrypt.md) - Encrypt plain text yaml files representing Kubernetes objects consisting of sensitive configuration. * [airshipctl secret generate](airshipctl_secret_generate.md) - Generate various secrets diff --git a/docs/source/cli/airshipctl_secret_decrypt.md b/docs/source/cli/airshipctl_secret_decrypt.md new file mode 100644 index 0000000..c0e9934 --- /dev/null +++ b/docs/source/cli/airshipctl_secret_decrypt.md @@ -0,0 +1,46 @@ +## airshipctl secret decrypt + +Decrypt encrypted yaml files into plaintext files representing Kubernetes objects consisting of sensitive data. + +### Synopsis + +Decrypt encrypted yaml files into plaintext files representing Kubernetes objects consisting of sensitive data. + +``` +airshipctl secret decrypt [flags] +``` + +### Examples + +``` + +# Decrypt all encrypted files in the manifests directory. +airshipctl secret decrypt + +# Decrypt encrypted file from src and write the plain text to a different dst file +airshipctl secret decrypt \ + --src /tmp/manifests/target/secrets/encrypted-qualified-secret.yaml \ + --dst /tmp/manifests/target/secrets/qualified-secret.yaml + +``` + +### Options + +``` + --dst string Path to the file or directory to store decrypted secrets. Defaults to src if empty. + -h, --help help for decrypt + --src string Path to the file or directory that has secrets in encrypted text that need to be decrypted. Defaults to the manifest location in airship config +``` + +### Options inherited from parent commands + +``` + --airshipconf string Path to file for airshipctl configuration. (default "$HOME/.airship/config") + --debug enable verbose output + --kubeconfig string Path to kubeconfig associated with airshipctl configuration. (default "$HOME/.airship/kubeconfig") +``` + +### SEE ALSO + +* [airshipctl secret](airshipctl_secret.md) - Manage secrets + diff --git a/docs/source/cli/airshipctl_secret_encrypt.md b/docs/source/cli/airshipctl_secret_encrypt.md new file mode 100644 index 0000000..28a92b6 --- /dev/null +++ b/docs/source/cli/airshipctl_secret_encrypt.md @@ -0,0 +1,46 @@ +## airshipctl secret encrypt + +Encrypt plain text yaml files representing Kubernetes objects consisting of sensitive configuration. + +### Synopsis + +Encrypt plain text yaml files representing Kubernetes objects consisting of sensitive configuration. + +``` +airshipctl secret encrypt [flags] +``` + +### Examples + +``` + +# Encrypt all kubernetes objects in the manifests directory. +airshipctl secret encrypt + +# Encrypt file from src and write to a different dst file +airshipctl secret encrypt \ + --src /tmp/manifests/target/secrets/qualified-secret.yaml \ + --dst /tmp/manifests/target/secrets/encrypted-qualified-secret.yaml + +``` + +### Options + +``` + --dst string Path to the file or directory that has encrypted secrets for decryption. Defaults to src if empty. + -h, --help help for encrypt + --src string Path to the file or directory that has secrets in plaintext that need to be encrypted. Defaults to the manifest location in airship config +``` + +### Options inherited from parent commands + +``` + --airshipconf string Path to file for airshipctl configuration. (default "$HOME/.airship/config") + --debug enable verbose output + --kubeconfig string Path to kubeconfig associated with airshipctl configuration. (default "$HOME/.airship/kubeconfig") +``` + +### SEE ALSO + +* [airshipctl secret](airshipctl_secret.md) - Manage secrets +