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 }