Skip to content

Commit

Permalink
Merge pull request #367 from mvshao/auditlog-strict
Browse files Browse the repository at this point in the history
Possibility of disabling audit log functionality per landscape
  • Loading branch information
kyma-bot authored Sep 10, 2024
2 parents c9900b4 + fd9388d commit 7da0a88
Show file tree
Hide file tree
Showing 10 changed files with 247 additions and 31 deletions.
7 changes: 4 additions & 3 deletions api/v1/runtime_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,10 @@ const (
ConditionReasonSerializationError = RuntimeConditionReason("SerializationErr")
ConditionReasonDeleted = RuntimeConditionReason("Deleted")

ConditionReasonAdministratorsConfigured = RuntimeConditionReason("AdministratorsConfigured")
ConditionReasonAuditLogConfigured = RuntimeConditionReason("AuditLogConfigured")
ConditionReasonAuditLogError = RuntimeConditionReason("AuditLogErr")
ConditionReasonAdministratorsConfigured = RuntimeConditionReason("AdministratorsConfigured")
ConditionReasonAuditLogConfigured = RuntimeConditionReason("AuditLogConfigured")
ConditionReasonAuditLogError = RuntimeConditionReason("AuditLogErr")
ConditionReasonAuditLogMissingRegionMapping = RuntimeConditionReason("AuditLogMissingRegionMappingErr")
)

//+kubebuilder:object:root=true
Expand Down
62 changes: 59 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package main

import (
"encoding/json"
"flag"
"fmt"
"io"
Expand All @@ -27,6 +28,7 @@ import (
gardener_apis "github.com/gardener/gardener/pkg/client/core/clientset/versioned/typed/core/v1beta1"
"github.com/go-playground/validator/v10"
infrastructuremanagerv1 "github.com/kyma-project/infrastructure-manager/api/v1"
"github.com/kyma-project/infrastructure-manager/internal/auditlogging"
kubeconfig_controller "github.com/kyma-project/infrastructure-manager/internal/controller/kubeconfig"
"github.com/kyma-project/infrastructure-manager/internal/controller/metrics"
runtime_controller "github.com/kyma-project/infrastructure-manager/internal/controller/runtime"
Expand Down Expand Up @@ -76,6 +78,7 @@ func main() {
var enableRuntimeReconciler bool
var converterConfigFilepath string
var shootSpecDumpEnabled bool
var auditLogMandatory bool

flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
Expand All @@ -90,6 +93,7 @@ func main() {
flag.BoolVar(&enableRuntimeReconciler, "runtime-reconciler-enabled", defaultRuntimeReconcilerEnabled, "Feature flag for all runtime reconciler functionalities")
flag.StringVar(&converterConfigFilepath, "converter-config-filepath", "/converter-config/converter_config.json", "A file path to the gardener shoot converter configuration.")
flag.BoolVar(&shootSpecDumpEnabled, "shoot-spec-dump-enabled", false, "Feature flag to allow persisting specs of created shoots")
flag.BoolVar(&auditLogMandatory, "audit-log-mandatory", true, "Feature flag to enable strict mode for audit log configuration")

opts := zap.Options{
Development: true,
Expand Down Expand Up @@ -171,10 +175,17 @@ func main() {
os.Exit(1)
}

err = validateAuditLogConfiguration(converterConfig.AuditLog.TenantConfigPath)
if err != nil {
setupLog.Error(err, "invalid Audit Log configuration")
os.Exit(1)
}

cfg := fsm.RCCfg{
Finalizer: infrastructuremanagerv1.Finalizer,
ShootNamesapace: gardenerNamespace,
ConverterConfig: converterConfig,
Finalizer: infrastructuremanagerv1.Finalizer,
ShootNamesapace: gardenerNamespace,
ConverterConfig: converterConfig,
AuditLogMandatory: auditLogMandatory,
}
if shootSpecDumpEnabled {
cfg.PVCPath = "/testdata/kim"
Expand Down Expand Up @@ -238,3 +249,48 @@ func initGardenerClients(kubeconfigPath string, namespace string) (client.Client
}
return gardenerClient, shootClient, dynamicKubeconfigAPI, nil
}

func validateAuditLogConfiguration(tenantConfigPath string) error {
getReaderCloser := func() (io.ReadCloser, error) {
return os.Open(tenantConfigPath)
}

f, err := getReaderCloser()

defer func(f io.ReadCloser) {
_ = f.Close()
}(f)

if err != nil {
setupLog.Error(err, "unable to open Audit Log configuration file")
return err
}

var auditLogConfig map[string]map[string]auditlogging.AuditLogData

if err = json.NewDecoder(f).Decode(&auditLogConfig); err != nil {
setupLog.Error(err, "unable to decode Audit Log configuration")
return err
}

if err = validateAuditLogDataMap(auditLogConfig); err != nil {
setupLog.Error(err, "invalid audit log configuration")
return err
}

return err
}

func validateAuditLogDataMap(data map[string]map[string]auditlogging.AuditLogData) error {
validate := validator.New(validator.WithRequiredStructEnabled())

for _, nestedMap := range data {
for _, auditLogData := range nestedMap {
if err := validate.Struct(auditLogData); err != nil {
return err
}
}
}

return nil
}
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ You can configure the Infrastructure Manager deployment with the following argum
4. `gardener-request-timeout` - specifies the timeout for requests to Gardener. Default value is `60s`.
5. `runtime-reconciler-enabled` - feature flag responsible for enabling the runtime reconciler. Default value is `true`.
6. `shoot-spec-dump-enabled` - feature flag responsible for enabling the shoot spec dump. Default value is `false`.
7. `audit-log-mandatory` - feature flag responsible for enabling the Audit Log strict config. Default value is `true`.


See [manager_gardener_secret_patch.yaml](../config/default/manager_gardener_secret_patch.yaml) for default values.
Expand Down
10 changes: 6 additions & 4 deletions internal/auditlogging/auditlogging.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const (
auditlogExtensionType = "shoot-auditlog-service"
)

var ErrMissingMapping = errors.New("missing mapping for selected region in provider config")

//go:generate mockery --name=AuditLogging
type AuditLogging interface {
Enable(ctx context.Context, shoot *gardener.Shoot) (bool, error)
Expand All @@ -45,9 +47,9 @@ type auditLogConfig struct {
}

type AuditLogData struct {
TenantID string `json:"tenantID"`
ServiceURL string `json:"serviceURL"`
SecretName string `json:"secretName"`
TenantID string `json:"tenantID" validate:"required"`
ServiceURL string `json:"serviceURL" validate:"required,url"`
SecretName string `json:"secretName" validate:"required"`
}

type AuditlogExtensionConfig struct {
Expand Down Expand Up @@ -141,7 +143,7 @@ func ApplyAuditLogConfig(shoot *gardener.Shoot, auditConfigFromFile map[string]m

tenant, ok := providerConfig[auditID]
if !ok {
return false, fmt.Errorf("auditlog config for region %s, provider %s is empty", auditID, providerType)
return false, ErrMissingMapping
}

changedExt, err := configureExtension(shoot, tenant)
Expand Down
5 changes: 3 additions & 2 deletions internal/auditlogging/tests/auditlogging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package tests
import (
"context"
"fmt"
"testing"

gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1"
"github.com/kyma-project/infrastructure-manager/internal/auditlogging"
"github.com/kyma-project/infrastructure-manager/internal/auditlogging/mocks"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/utils/ptr"
"testing"
)

func TestEnable(t *testing.T) {
Expand Down Expand Up @@ -139,7 +140,7 @@ func TestApplyAuditLogConfig(t *testing.T) {

// then
require.False(t, annotated)
require.Equal(t, err, fmt.Errorf("auditlog config for region region, provider aws is empty"))
require.Equal(t, err, auditlogging.ErrMissingMapping)
})
}

Expand Down
7 changes: 4 additions & 3 deletions internal/controller/runtime/fsm/runtime_fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ type writerGetter = func(filePath string) (io.Writer, error)

// runtime reconciler specific configuration
type RCCfg struct {
Finalizer string
PVCPath string
ShootNamesapace string
Finalizer string
PVCPath string
ShootNamesapace string
AuditLogMandatory bool
shoot.ConverterConfig
}

Expand Down
46 changes: 37 additions & 9 deletions internal/controller/runtime/fsm/runtime_fsm_configure_auditlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"

imv1 "github.com/kyma-project/infrastructure-manager/api/v1"
"github.com/kyma-project/infrastructure-manager/internal/auditlogging"
"github.com/pkg/errors"
ctrl "sigs.k8s.io/controller-runtime"
)

Expand All @@ -24,19 +26,45 @@ func sFnConfigureAuditLog(ctx context.Context, m *fsm, s *systemState) (stateFn,
return updateStatusAndRequeueAfter(gardenerRequeueDuration)
}

if err != nil {
m.log.Error(err, "Failed to configure Audit Log")
s.instance.UpdateStatePending(
imv1.ConditionTypeAuditLogConfigured,
imv1.ConditionReasonAuditLogError,
"False",
err.Error(),
)
if err != nil { //nolint:nestif
errorMessage := err.Error()
if errors.Is(err, auditlogging.ErrMissingMapping) {
if m.RCCfg.AuditLogMandatory {
m.log.Error(err, "Failed to configure Audit Log, missing region mapping for this shoot", "AuditLogMandatory", m.RCCfg.AuditLogMandatory, "providerType", s.shoot.Spec.Provider.Type, "region", s.shoot.Spec.Region)
s.instance.UpdateStatePending(
imv1.ConditionTypeAuditLogConfigured,
imv1.ConditionReasonAuditLogMissingRegionMapping,
"False",
errorMessage,
)
} else {
m.log.Info(errorMessage, "Audit Log was not configured, missing region mapping for this shoot.", "AuditLogMandatory", m.RCCfg.AuditLogMandatory, "providerType", s.shoot.Spec.Provider.Type, "region", s.shoot.Spec.Region)
s.instance.UpdateStateReady(
imv1.ConditionTypeAuditLogConfigured,
imv1.ConditionReasonAuditLogMissingRegionMapping,
"Missing region mapping for this shoot. Audit Log is not mandatory. Skipping configuration")
}
} else {
if m.RCCfg.AuditLogMandatory {
m.log.Error(err, "Failed to configure Audit Log", "AuditLogMandatory", m.RCCfg.AuditLogMandatory)
s.instance.UpdateStatePending(
imv1.ConditionTypeAuditLogConfigured,
imv1.ConditionReasonAuditLogError,
"False",
errorMessage)
} else {
m.log.Info(errorMessage, "AuditLogMandatory", m.RCCfg.AuditLogMandatory)
s.instance.UpdateStateReady(
imv1.ConditionTypeAuditLogConfigured,
imv1.ConditionReasonAuditLogError,
"Configuration of Audit Log is not mandatory, error for context: "+errorMessage)
}
}
} else {
s.instance.UpdateStateReady(
imv1.ConditionTypeAuditLogConfigured,
imv1.ConditionReasonAuditLogConfigured,
"Audit Log configured successfully",
"Audit Log state completed successfully",
)
}

Expand Down
Loading

0 comments on commit 7da0a88

Please sign in to comment.