github.com/argoproj/argo-cd/v3@v3.2.1/util/argo/audit_logger.go (about)

     1  package argo
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	log "github.com/sirupsen/logrus"
     9  	corev1 "k8s.io/api/core/v1"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"k8s.io/apimachinery/pkg/runtime/schema"
    12  	"k8s.io/apimachinery/pkg/types"
    13  	"k8s.io/client-go/kubernetes"
    14  
    15  	"github.com/argoproj/argo-cd/v3/pkg/apis/application"
    16  
    17  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    18  )
    19  
    20  type AuditLogger struct {
    21  	kIf            kubernetes.Interface
    22  	component      string
    23  	enableEventLog map[string]bool
    24  }
    25  
    26  type EventInfo struct {
    27  	Type   string
    28  	Reason string
    29  }
    30  
    31  type ObjectRef struct {
    32  	Name            string
    33  	Namespace       string
    34  	ResourceVersion string
    35  	UID             types.UID
    36  }
    37  
    38  const (
    39  	EventReasonStatusRefreshed    = "StatusRefreshed"
    40  	EventReasonResourceCreated    = "ResourceCreated"
    41  	EventReasonResourceUpdated    = "ResourceUpdated"
    42  	EventReasonResourceDeleted    = "ResourceDeleted"
    43  	EventReasonResourceActionRan  = "ResourceActionRan"
    44  	EventReasonOperationStarted   = "OperationStarted"
    45  	EventReasonOperationCompleted = "OperationCompleted"
    46  )
    47  
    48  func (l *AuditLogger) logEvent(objMeta ObjectRef, gvk schema.GroupVersionKind, info EventInfo, message string, logFields map[string]string, eventLabels map[string]string) {
    49  	logCtx := log.WithFields(log.Fields{
    50  		"type":   info.Type,
    51  		"reason": info.Reason,
    52  	})
    53  	for field, val := range logFields {
    54  		logCtx = logCtx.WithField(field, val)
    55  	}
    56  
    57  	switch gvk.Kind {
    58  	case application.ApplicationKind:
    59  		logCtx = logCtx.WithField("application", objMeta.Name)
    60  	case application.AppProjectKind:
    61  		logCtx = logCtx.WithField("project", objMeta.Name)
    62  	default:
    63  		logCtx = logCtx.WithField("name", objMeta.Name)
    64  	}
    65  	t := metav1.Time{Time: time.Now()}
    66  	event := corev1.Event{
    67  		ObjectMeta: metav1.ObjectMeta{
    68  			Name:        fmt.Sprintf("%v.%x", objMeta.Name, t.UnixNano()),
    69  			Labels:      eventLabels,
    70  			Annotations: logFields,
    71  		},
    72  		Source: corev1.EventSource{
    73  			Component: l.component,
    74  		},
    75  		InvolvedObject: corev1.ObjectReference{
    76  			Kind:            gvk.Kind,
    77  			Name:            objMeta.Name,
    78  			Namespace:       objMeta.Namespace,
    79  			ResourceVersion: objMeta.ResourceVersion,
    80  			APIVersion:      gvk.GroupVersion().String(),
    81  			UID:             objMeta.UID,
    82  		},
    83  		FirstTimestamp: t,
    84  		LastTimestamp:  t,
    85  		Count:          1,
    86  		Message:        message,
    87  		Type:           info.Type,
    88  		Reason:         info.Reason,
    89  	}
    90  	logCtx.Info(message)
    91  	_, err := l.kIf.CoreV1().Events(objMeta.Namespace).Create(context.Background(), &event, metav1.CreateOptions{})
    92  	if err != nil {
    93  		logCtx.Errorf("Unable to create audit event: %v", err)
    94  		return
    95  	}
    96  }
    97  
    98  func (l *AuditLogger) enableK8SEventLog(info EventInfo) bool {
    99  	return l.enableEventLog["all"] || l.enableEventLog[info.Reason]
   100  }
   101  
   102  func (l *AuditLogger) LogAppEvent(app *v1alpha1.Application, info EventInfo, message, user string, eventLabels map[string]string) {
   103  	if !l.enableK8SEventLog(info) {
   104  		return
   105  	}
   106  
   107  	objectMeta := ObjectRef{
   108  		Name:            app.Name,
   109  		Namespace:       app.Namespace,
   110  		ResourceVersion: app.ResourceVersion,
   111  		UID:             app.UID,
   112  	}
   113  	fields := map[string]string{
   114  		"dest-server":    app.Spec.Destination.Server,
   115  		"dest-namespace": app.Spec.Destination.Namespace,
   116  	}
   117  	if user != "" {
   118  		fields["user"] = user
   119  	}
   120  	l.logEvent(objectMeta, v1alpha1.ApplicationSchemaGroupVersionKind, info, message, fields, eventLabels)
   121  }
   122  
   123  func (l *AuditLogger) LogAppSetEvent(app *v1alpha1.ApplicationSet, info EventInfo, message, user string) {
   124  	if !l.enableK8SEventLog(info) {
   125  		return
   126  	}
   127  
   128  	objectMeta := ObjectRef{
   129  		Name:            app.Name,
   130  		Namespace:       app.Namespace,
   131  		ResourceVersion: app.ResourceVersion,
   132  		UID:             app.UID,
   133  	}
   134  	fields := map[string]string{}
   135  	if user != "" {
   136  		fields["user"] = user
   137  	}
   138  	l.logEvent(objectMeta, v1alpha1.ApplicationSetSchemaGroupVersionKind, info, message, fields, nil)
   139  }
   140  
   141  func (l *AuditLogger) LogResourceEvent(res *v1alpha1.ResourceNode, info EventInfo, message, user string) {
   142  	if !l.enableK8SEventLog(info) {
   143  		return
   144  	}
   145  
   146  	objectMeta := ObjectRef{
   147  		Name:            res.Name,
   148  		Namespace:       res.Namespace,
   149  		ResourceVersion: res.Version,
   150  		UID:             types.UID(res.UID),
   151  	}
   152  	fields := map[string]string{}
   153  	if user != "" {
   154  		fields["user"] = user
   155  	}
   156  	l.logEvent(objectMeta, schema.GroupVersionKind{
   157  		Group:   res.Group,
   158  		Version: res.Version,
   159  		Kind:    res.Kind,
   160  	}, info, message, fields, nil)
   161  }
   162  
   163  func (l *AuditLogger) LogAppProjEvent(proj *v1alpha1.AppProject, info EventInfo, message, user string) {
   164  	if !l.enableK8SEventLog(info) {
   165  		return
   166  	}
   167  
   168  	objectMeta := ObjectRef{
   169  		Name:            proj.Name,
   170  		Namespace:       proj.Namespace,
   171  		ResourceVersion: proj.ResourceVersion,
   172  		UID:             proj.UID,
   173  	}
   174  	fields := map[string]string{}
   175  	if user != "" {
   176  		fields["user"] = user
   177  	}
   178  	l.logEvent(objectMeta, v1alpha1.AppProjectSchemaGroupVersionKind, info, message, nil, nil)
   179  }
   180  
   181  func NewAuditLogger(kIf kubernetes.Interface, component string, enableK8sEvent []string) *AuditLogger {
   182  	return &AuditLogger{
   183  		kIf:            kIf,
   184  		component:      component,
   185  		enableEventLog: setK8sEventList(enableK8sEvent),
   186  	}
   187  }
   188  
   189  func setK8sEventList(enableK8sEvent []string) map[string]bool {
   190  	enableK8sEventList := make(map[string]bool)
   191  
   192  	for _, event := range enableK8sEvent {
   193  		switch event {
   194  		case "all":
   195  			enableK8sEventList = map[string]bool{
   196  				"all": true,
   197  			}
   198  			return enableK8sEventList
   199  		case "none":
   200  			enableK8sEventList = map[string]bool{}
   201  			return enableK8sEventList
   202  		}
   203  
   204  		enableK8sEventList[event] = true
   205  	}
   206  
   207  	return enableK8sEventList
   208  }
   209  
   210  func DefaultEnableEventList() []string {
   211  	return []string{"all"}
   212  }