1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
910use std::path::PathBuf;
11use std::sync::Arc;
1213use clap::ValueEnum;
14use mz_aws_secrets_controller::AwsSecretsClient;
15use mz_orchestrator_kubernetes::secrets::KubernetesSecretsReader;
16use mz_orchestrator_process::secrets::ProcessSecretsReader;
17use mz_secrets::SecretsReader;
1819#[derive(clap::Parser, Clone, Debug)]
20pub struct SecretsReaderCliArgs {
21/// The secrets reader implementation to use.
22#[structopt(long, value_enum, env = "SECRETS_READER")]
23pub secrets_reader: SecretsControllerKind,
24/// When using the process secrets reader, the directory on the filesystem
25 /// where secrets are stored.
26#[structopt(
27 long,
28 required_if_eq("secrets_reader", "local-file"),
29 env = "SECRETS_READER_LOCAL_FILE_DIR"
30)]
31pub secrets_reader_local_file_dir: Option<PathBuf>,
32/// When using the Kubernetes secrets reader, the Kubernetes context to
33 /// load.
34#[structopt(
35 long,
36 required_if_eq("secrets_reader", "kubernetes"),
37 env = "SECRETS_READER_KUBERNETES_CONTEXT"
38)]
39pub secrets_reader_kubernetes_context: Option<String>,
40/// When using the AWS secrets reader, we need both of the following.
41#[structopt(
42 long,
43 required_if_eq("secrets_reader", "aws-secrets-manager"),
44 env = "SECRETS_READER_AWS_PREFIX"
45)]
46pub secrets_reader_aws_prefix: Option<String>,
47/// When using the Kubernetes secrets reader, the prefix to use for secret
48 /// names.
49#[structopt(long, env = "SECRETS_READER_NAME_PREFIX")]
50pub secrets_reader_name_prefix: Option<String>,
51}
5253#[derive(ValueEnum, Debug, Clone, Copy)]
54pub enum SecretsControllerKind {
55 LocalFile,
56 Kubernetes,
57 AwsSecretsManager,
58}
5960impl SecretsReaderCliArgs {
61/// Loads the secrets reader specified by the command-line arguments.
62pub async fn load(self) -> Result<Arc<dyn SecretsReader>, anyhow::Error> {
63match self.secrets_reader {
64 SecretsControllerKind::LocalFile => {
65let dir = self.secrets_reader_local_file_dir.expect("clap enforced");
66Ok(Arc::new(ProcessSecretsReader::new(dir)))
67 }
68 SecretsControllerKind::Kubernetes => {
69let context = self
70.secrets_reader_kubernetes_context
71 .expect("clap enforced");
72Ok(Arc::new(
73 KubernetesSecretsReader::new(context, self.secrets_reader_name_prefix).await?,
74 ))
75 }
76 SecretsControllerKind::AwsSecretsManager => {
77let prefix = self.secrets_reader_aws_prefix.expect("clap enforced");
78Ok(Arc::new(AwsSecretsClient::new(&prefix).await))
79 }
80 }
81 }
8283/// Turn this struct back into arguments. Useful for passing through to other services.
84 ///
85 /// Expects the correct arguments to be filled in, based on the `clap` requirements.
86pub fn to_flags(&self) -> Vec<String> {
87match self.secrets_reader {
88 SecretsControllerKind::LocalFile => {
89vec![
90"--secrets-reader=local-file".to_string(),
91format!(
92"--secrets-reader-local-file-dir={}",
93self.secrets_reader_local_file_dir
94 .as_ref()
95 .expect("initialized correctly")
96 .display()
97 ),
98 ]
99 }
100 SecretsControllerKind::Kubernetes => {
101vec![
102"--secrets-reader=kubernetes".to_string(),
103format!(
104"--secrets-reader-kubernetes-context={}",
105self.secrets_reader_kubernetes_context
106 .as_ref()
107 .expect("initialized correctly")
108 ),
109 ]
110 }
111 SecretsControllerKind::AwsSecretsManager => {
112vec![
113"--secrets-reader=aws-secrets-manager".to_string(),
114format!(
115"--secrets-reader-aws-prefix={}",
116self.secrets_reader_aws_prefix
117 .as_ref()
118 .expect("initialized correctly")
119 ),
120 ]
121 }
122 }
123 }
124}