Skip to content

Commit

Permalink
feat: implement conditional secret management (#2517)
Browse files Browse the repository at this point in the history
Signed-off-by: Faeka Ansari <[email protected]>
Signed-off-by: Remington Breeze <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Co-authored-by: Remington Breeze <[email protected]>
Co-authored-by: Kent Rancourt <[email protected]>
  • Loading branch information
3 people committed Sep 11, 2024
1 parent a64eb0e commit c561668
Show file tree
Hide file tree
Showing 15 changed files with 1,281 additions and 1,201 deletions.
1 change: 1 addition & 0 deletions api/service/v1alpha1/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ message ArgoCDShard {

message GetConfigResponse {
map<string, ArgoCDShard> argocd_shards = 1;
bool secret_management_enabled = 2;
}

message GetPublicConfigRequest {}
Expand Down
1 change: 1 addition & 0 deletions charts/kargo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ the Kargo controller is running.
| `api.annotations` | Annotations to add to the api resources. Merges with `global.annotations`, allowing you to override or add to the global annotations. | `{}` |
| `api.podLabels` | Optional labels to add to pods. Merges with `global.podLabels`, allowing you to override or add to the global labels. | `{}` |
| `api.podAnnotations` | Optional annotations to add to pods. Merges with `global.podAnnotations`, allowing you to override or add to the global annotations. | `{}` |
| `api.enableSecretManagement` | Specifies whether Secret management is enabled. This affects the API server's ability to manage repository credentials and other Project-level Secrets, such as those used by AnalysisRuns for verification purposes. If using GitOps to manage Kargo Projects declaratively, the API's Secret management capabilities are not needed and can be disabled to effectively reduce the API server's attackable surface. | `true` |
| `api.resources` | Resources limits and requests for the api containers. | `{}` |
| `api.nodeSelector` | Node selector for api pods. Defaults to `global.nodeSelector`. | `{}` |
| `api.tolerations` | Tolerations for api pods. Defaults to `global.tolerations`. | `[]` |
Expand Down
2 changes: 2 additions & 0 deletions charts/kargo/templates/api/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ rules:
- ""
resources:
- configmaps
{{- if .Values.api.enableSecretManagement }}
- secrets
{{- end }}
- serviceaccounts
verbs:
- "*"
Expand Down
3 changes: 3 additions & 0 deletions charts/kargo/templates/api/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ data:
TLS_CERT_PATH: /etc/kargo/tls.crt
TLS_KEY_PATH: /etc/kargo/tls.key
{{- end }}
{{- if .Values.api.enableSecretManagement }}
ENABLE_SECRET_MANAGEMENT: "true"
{{- end }}
PERMISSIVE_CORS_POLICY_ENABLED: {{ quote .Values.api.enablePermissiveCORSPolicy }}
{{- if .Values.api.adminAccount.enabled }}
ADMIN_ACCOUNT_ENABLED: "true"
Expand Down
3 changes: 3 additions & 0 deletions charts/kargo/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ api:
## @param api.podAnnotations Optional annotations to add to pods. Merges with `global.podAnnotations`, allowing you to override or add to the global annotations.
podAnnotations: {}

## @param api.enableSecretManagement Specifies whether Secret management is enabled. This affects the API server's ability to manage repository credentials and other Project-level Secrets, such as those used by AnalysisRuns for verification purposes. If using GitOps to manage Kargo Projects declaratively, the API's Secret management capabilities are not needed and can be disabled to effectively reduce the API server's attackable surface.
enableSecretManagement: true

## @param api.resources Resources limits and requests for the api containers.
resources: {}
# limits:
Expand Down
2 changes: 2 additions & 0 deletions internal/api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type StandardConfig struct {

type ServerConfig struct {
StandardConfig
EnableSecretManagement bool
LocalMode bool // LocalMode is true if the server is running as a non-containerized process
TLSConfig *TLSConfig
OIDCConfig *oidc.Config
Expand All @@ -32,6 +33,7 @@ type ServerConfig struct {
func ServerConfigFromEnv() ServerConfig {
cfg := ServerConfig{}
envconfig.MustProcess("", &cfg.StandardConfig)
cfg.EnableSecretManagement = types.MustParseBool(os.GetEnv("ENABLE_SECRET_MANAGEMENT", "false"))
if types.MustParseBool(os.GetEnv("TLS_ENABLED", "false")) {
tlsCfg := TLSConfigFromEnv()
cfg.TLSConfig = &tlsCfg
Expand Down
9 changes: 9 additions & 0 deletions internal/api/delete_credentials_v1alpha1.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"errors"
"fmt"

"connectrpc.com/connect"
Expand All @@ -15,6 +16,14 @@ func (s *server) DeleteCredentials(
ctx context.Context,
req *connect.Request[svcv1alpha1.DeleteCredentialsRequest],
) (*connect.Response[svcv1alpha1.DeleteCredentialsResponse], error) {
// Check if secret management is enabled
if !s.cfg.EnableSecretManagement {
return nil, connect.NewError(
connect.CodeUnimplemented,
errors.New("secret management is not enabled"),
)
}

project := req.Msg.GetProject()
if err := validateFieldNotEmpty("project", project); err != nil {
return nil, err
Expand Down
3 changes: 2 additions & 1 deletion internal/api/get_config_v1alpha1.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ func (s *server) GetConfig(
*connect.Request[svcv1alpha1.GetConfigRequest],
) (*connect.Response[svcv1alpha1.GetConfigResponse], error) {
resp := svcv1alpha1.GetConfigResponse{
ArgocdShards: make(map[string]*svcv1alpha1.ArgoCDShard),
ArgocdShards: make(map[string]*svcv1alpha1.ArgoCDShard),
SecretManagementEnabled: s.cfg.EnableSecretManagement,
}
for shardName, url := range s.cfg.ArgoCDConfig.URLs {
resp.ArgocdShards[shardName] = &svcv1alpha1.ArgoCDShard{
Expand Down
8 changes: 8 additions & 0 deletions internal/api/get_credentials_v1alpha1.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ func (s *server) GetCredentials(
ctx context.Context,
req *connect.Request[svcv1alpha1.GetCredentialsRequest],
) (*connect.Response[svcv1alpha1.GetCredentialsResponse], error) {
// Check if secret management is enabled
if !s.cfg.EnableSecretManagement {
return nil, connect.NewError(
connect.CodeUnimplemented,
fmt.Errorf("secret management is not enabled"),
)
}

project := req.Msg.GetProject()
if err := validateFieldNotEmpty("project", project); err != nil {
return nil, err
Expand Down
4 changes: 4 additions & 0 deletions internal/api/get_credentials_v1alpha1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/fake"

kargoapi "github.com/akuity/kargo/api/v1alpha1"
"github.com/akuity/kargo/internal/api/config"
"github.com/akuity/kargo/internal/api/kubernetes"
"github.com/akuity/kargo/internal/api/validation"
libCreds "github.com/akuity/kargo/internal/credentials"
Expand Down Expand Up @@ -275,6 +276,9 @@ func TestGetCredentials(t *testing.T) {
svr := &server{
client: client,
externalValidateProjectFn: validation.ValidateProject,
cfg: config.ServerConfig{
EnableSecretManagement: true,
},
}
res, err := (svr).GetCredentials(ctx, connect.NewRequest(testCase.req))
testCase.assertions(t, res, err)
Expand Down
8 changes: 8 additions & 0 deletions internal/api/list_credentials_v1alpha1.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ func (s *server) ListCredentials(
ctx context.Context,
req *connect.Request[svcv1alpha1.ListCredentialsRequest],
) (*connect.Response[svcv1alpha1.ListCredentialsResponse], error) {
// Check if secret management is enabled
if !s.cfg.EnableSecretManagement {
return nil, connect.NewError(
connect.CodeUnimplemented,
fmt.Errorf("secret management is not enabled"),
)
}

project := req.Msg.GetProject()
if err := validateFieldNotEmpty("project", project); err != nil {
return nil, err
Expand Down
8 changes: 8 additions & 0 deletions internal/api/update_credentials_v1alpha1.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ func (s *server) UpdateCredentials(
ctx context.Context,
req *connect.Request[svcv1alpha1.UpdateCredentialsRequest],
) (*connect.Response[svcv1alpha1.UpdateCredentialsResponse], error) {
// Check if secret management is enabled
if !s.cfg.EnableSecretManagement {
return nil, connect.NewError(
connect.CodeUnimplemented,
fmt.Errorf("secret management is not enabled"),
)
}

credsUpdate := credentialsUpdate{
project: req.Msg.GetProject(),
name: req.Msg.GetName(),
Expand Down
Loading

0 comments on commit c561668

Please sign in to comment.