Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement backend namespace and duration configuration #30

Merged
merged 5 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions cmd/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,18 @@ type Options struct {
Backend BackendConfig
}

// BackendConfig defines the exposed backend configurations
type BackendConfig struct {
Port int `env:"EPHEMERAL_BACKEND_PORT, default=8888"`
// Port defines the port used to listen to http requests sent to this service
Port int `env:"EPHEMERAL_BACKEND_PORT, default=8888"`
// Kubeconfig is an optional configuration to allow connecting to a k8s cluster
// remotelly
Kubeconfig string `env:"KUBECONFIG"`
// Namespace must point to the namespace where this backend service is running
Namespace string `env:"EPHEMERAL_BACKEND_NAMESPACE, required"`
// DefaultAccessDuration defines the default duration to be used when creating
// AccessRequests
DefaultAccessDuration time.Duration `env:"EPHEMERAL_BACKEND_DEFAULT_ACCESS_DURATION, default=4h"`
leoluz marked this conversation as resolved.
Show resolved Hide resolved
}

// LogConfig defines the log configurations
Expand Down Expand Up @@ -116,7 +125,7 @@ func run(cmd *cobra.Command, args []string) error {
return fmt.Errorf("error creating a new k8s persister: %w", err)
}

service := backend.NewDefaultService(persister, logger, "TODO: get namespace from config or env var")
service := backend.NewDefaultService(persister, logger, opts.Backend.Namespace, opts.Backend.DefaultAccessDuration)
handler := backend.NewAPIHandler(service, logger)

cli := humacli.New(func(hooks humacli.Hooks, options *BackendConfig) {
Expand Down
10 changes: 9 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/argoproj-labs/ephemeral-access/cmd/backend"
"github.com/argoproj-labs/ephemeral-access/cmd/controller"
"github.com/argoproj-labs/ephemeral-access/pkg/log"
"github.com/spf13/cobra"
)

Expand All @@ -18,13 +19,20 @@ func main() {
},
DisableAutoGenTag: true,
SilenceUsage: true,
SilenceErrors: true,
}

command.AddCommand(backend.NewCommand())
command.AddCommand(controller.NewCommand())

if err := command.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
msg := "ephemeral-access execution error"
logger, logerr := log.NewLogger()
if logerr != nil {
fmt.Fprintf(os.Stderr, "%s: %s", msg, err)
os.Exit(1)
}
logger.Error(err, msg)
os.Exit(1)
}
}
23 changes: 23 additions & 0 deletions config/backend/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-cm
labels:
app.kubernetes.io/name: argocd-ephemeral-access
app.kubernetes.io/managed-by: kustomize
# data:
## Log configurations
# backend.log.level: info
# backend.log.format: json

## The API server port
# backend.port: '8888'

## The address the metric endpoint binds to
# backend.metrics.address: :8883

## If set the metrics endpoint is served securely
# backend.metrics.secure: 'true'

## Defines the default duration to be used when creating AccessRequests
# backend.defaultAccessDuration: 4h
20 changes: 15 additions & 5 deletions config/backend/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,43 @@ spec:
- name: EPHEMERAL_LOG_LEVEL
valueFrom:
configMapKeyRef:
name: config-cm
name: backend-cm
key: backend.log.level
optional: true
- name: EPHEMERAL_LOG_FORMAT
valueFrom:
configMapKeyRef:
name: config-cm
name: backend-cm
key: backend.log.format
optional: true
- name: EPHEMERAL_METRICS_ADDR
valueFrom:
configMapKeyRef:
name: config-cm
name: backend-cm
key: backend.metrics.address
optional: true
- name: EPHEMERAL_METRICS_SECURE
valueFrom:
configMapKeyRef:
name: config-cm
name: backend-cm
key: backend.metrics.secure
optional: true
- name: EPHEMERAL_BACKEND_PORT
valueFrom:
configMapKeyRef:
name: config-cm
name: backend-cm
key: backend.port
optional: true
- name: EPHEMERAL_BACKEND_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: EPHEMERAL_BACKEND_DEFAULT_ACCESS_DURATION
valueFrom:
configMapKeyRef:
name: backend-cm
key: backend.defaultAccessDuration
optional: true
image: argoproj-labs/argocd-ephemeral-access:latest
imagePullPolicy: Always
name: backend
Expand Down
1 change: 1 addition & 0 deletions config/backend/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- config.yaml
- deployment.yaml
- metrics_service.yaml
- role_binding.yaml
Expand Down
5 changes: 0 additions & 5 deletions config/config/kustomization.yaml

This file was deleted.

24 changes: 9 additions & 15 deletions config/config/config.yaml → config/controller/config.yaml
Original file line number Diff line number Diff line change
@@ -1,38 +1,32 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: config-cm
name: controller-cm
labels:
app.kubernetes.io/name: argocd-ephemeral-access
app.kubernetes.io/managed-by: kustomize
data:
{}
### Log configurations
# backend.log.level: info
# backend.log.format: json
# data:
## Log configurations
# controller.log.level: info
# controller.log.format: json

### Backend configurations
## The API server port.
# backend.port: '8888'
## The address the metric endpoint binds to.
# backend.metrics.address: :8883
## If set the metrics endpoint is served securely.
# backend.metrics.secure: 'true'

# ### Controller configurations
## The controler server port.
# controller.port: '8081'

## Enable leader election for controller manager.
# controller.leader.election.enabled: 'true'

## The address the probe endpoint binds to.
# controller.health.probe.address: :8082

## If set, HTTP/2 will be enabled for the metrics and webhook servers.
# controller.http2.enabled: 'true'

## Determines the interval the controller will requeue an AccessRequest.
# controller.requeue.interval: 1s

## The address the metric endpoint binds to.
# controller.metrics.address: :8083

## If set the metrics endpoint is served securely.
# controller.metrics.secure: 'true'
18 changes: 9 additions & 9 deletions config/controller/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,55 +30,55 @@ spec:
- name: EPHEMERAL_LOG_LEVEL
valueFrom:
configMapKeyRef:
name: config-cm
name: controller-cm
key: controller.log.level
optional: true
- name: EPHEMERAL_LOG_FORMAT
valueFrom:
configMapKeyRef:
name: config-cm
name: controller-cm
key: controller.log.format
optional: true
- name: EPHEMERAL_METRICS_ADDR
valueFrom:
configMapKeyRef:
name: config-cm
name: controller-cm
key: controller.metrics.address
optional: true
- name: EPHEMERAL_METRICS_SECURE
valueFrom:
configMapKeyRef:
name: config-cm
name: controller-cm
key: controller.metrics.secure
optional: true
- name: EPHEMERAL_CONTROLLER_PORT
valueFrom:
configMapKeyRef:
name: config-cm
name: controller-cm
key: controller.port
optional: true
- name: EPHEMERAL_CONTROLLER_ENABLE_LEADER_ELECTION
valueFrom:
configMapKeyRef:
name: config-cm
name: controller-cm
key: controller.leader.election.enabled
optional: true
- name: EPHEMERAL_CONTROLLER_HEALTH_PROBE_ADDR
valueFrom:
configMapKeyRef:
name: config-cm
name: controller-cm
key: controller.health.probe.address
optional: true
- name: EPHEMERAL_CONTROLLER_ENABLE_HTTP2
valueFrom:
configMapKeyRef:
name: config-cm
name: controller-cm
key: controller.http2.enabled
optional: true
- name: EPHEMERAL_CONTROLLER_REQUEUE_INTERVAL
valueFrom:
configMapKeyRef:
name: config-cm
name: controller-cm
key: controller.requeue.interval
optional: true
image: argoproj-labs/argocd-ephemeral-access:latest
Expand Down
1 change: 1 addition & 0 deletions config/controller/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- config.yaml
- deployment.yaml
- metrics_service.yaml
- namespace.yaml
1 change: 0 additions & 1 deletion config/default/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ namePrefix: argocd-ephemeral-access-
resources:
- ../crd
- ../rbac
- ../config
- ../controller
- ../backend
images:
Expand Down
27 changes: 16 additions & 11 deletions internal/backend/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"slices"
"strings"
"time"

api "github.com/argoproj-labs/ephemeral-access/api/ephemeral-access/v1alpha1"
"github.com/argoproj-labs/ephemeral-access/pkg/log"
Expand Down Expand Up @@ -35,9 +36,10 @@ type AccessRequestKey struct {

// DefaultService is the real Service implementation
type DefaultService struct {
k8s Persister
logger log.Logger
namespace string
k8s Persister
logger log.Logger
namespace string
accessRequestDuration time.Duration
}

var requestStateOrder = map[api.Status]int{
Expand All @@ -51,11 +53,12 @@ var requestStateOrder = map[api.Status]int{
}

// NewDefaultService will return a new DefaultService instance.
func NewDefaultService(c Persister, l log.Logger, namespace string) *DefaultService {
func NewDefaultService(c Persister, l log.Logger, namespace string, arDuration time.Duration) *DefaultService {
return &DefaultService{
k8s: c,
logger: l,
namespace: namespace,
k8s: c,
logger: l,
namespace: namespace,
accessRequestDuration: arDuration,
}
}

Expand Down Expand Up @@ -153,21 +156,23 @@ func (s *DefaultService) CreateAccessRequest(ctx context.Context, key *AccessReq
GenerateName: s.getAccessRequestPrefix(key.Username, roleName),
},
Spec: api.AccessRequestSpec{
Duration: v1.Duration{
Duration: s.accessRequestDuration,
},
Role: api.TargetRole{
TemplateName: binding.Spec.RoleTemplateRef.Name,
Ordinal: binding.Spec.Ordinal,
FriendlyName: binding.Spec.FriendlyName,
},
Subject: api.Subject{
Username: key.Username,
},
Application: api.TargetApplication{
Name: key.ApplicationName,
Namespace: key.ApplicationNamespace,
},
Subject: api.Subject{
Username: key.Username,
},
},
}
//TODO: Set duration. Configurable by the users? Server Config?
ar, err := s.k8s.CreateAccessRequest(ctx, ar)
if err != nil {
return nil, fmt.Errorf("error creating access request from k8s: %w", err)
Expand Down
13 changes: 8 additions & 5 deletions internal/backend/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import (
)

const (
ControllerNamespace = "test-controller-ns"
ControllerNamespace = "test-controller-ns"
AccessRequestDuration = time.Minute
)

type serviceFixture struct {
Expand All @@ -34,7 +35,7 @@ func serviceSetup(t *testing.T) *serviceFixture {
logger := mocks.NewMockLogger(t)
logger.EXPECT().Debug(mock.Anything, mock.Anything).Maybe()
logger.EXPECT().Info(mock.Anything, mock.Anything).Maybe()
svc := backend.NewDefaultService(persister, logger, ControllerNamespace)
svc := backend.NewDefaultService(persister, logger, ControllerNamespace, AccessRequestDuration)
return &serviceFixture{
persister: persister,
logger: logger,
Expand All @@ -53,9 +54,10 @@ func TestServiceCreateAccessRequest(t *testing.T) {
Username: "some-user",
}
ab := newDefaultAccessBinding()
f.persister.EXPECT().CreateAccessRequest(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ar *api.AccessRequest) (*api.AccessRequest, error) {
return ar, nil
})
f.persister.EXPECT().CreateAccessRequest(mock.Anything, mock.Anything).
RunAndReturn(func(ctx context.Context, ar *api.AccessRequest) (*api.AccessRequest, error) {
return ar, nil
})

// When
result, err := f.svc.CreateAccessRequest(context.Background(), key, ab)
Expand All @@ -71,6 +73,7 @@ func TestServiceCreateAccessRequest(t *testing.T) {
assert.Equal(t, ab.Spec.FriendlyName, result.Spec.Role.FriendlyName)
assert.Equal(t, ab.Spec.Ordinal, result.Spec.Role.Ordinal)
assert.Equal(t, ab.Spec.RoleTemplateRef.Name, result.Spec.Role.TemplateName)
assert.Equal(t, AccessRequestDuration, result.Spec.Duration.Duration)
})
t.Run("will return error if k8s request fails", func(t *testing.T) {
// Given
Expand Down
Loading
Loading