Browse code

platformmanagement_public_704: Added basic auditing capabilities

Maciej Szulik authored on 2016/05/10 15:48:42
Showing 6 changed files
... ...
@@ -294,6 +294,16 @@ type MasterConfig struct {
294 294
 	// JenkinsPipelineConfig holds information about the default Jenkins template
295 295
 	// used for JenkinsPipeline build strategy.
296 296
 	JenkinsPipelineConfig JenkinsPipelineConfig
297
+
298
+	// AuditConfig holds information related to auditing capabilities.
299
+	AuditConfig AuditConfig
300
+}
301
+
302
+// AuditConfig holds configuration for the audit capabilities
303
+type AuditConfig struct {
304
+	// If this flag is set, audit log will be printed in the logs.
305
+	// The logs contains, method, user and a requested URL.
306
+	Enabled bool
297 307
 }
298 308
 
299 309
 // JenkinsPipelineConfig holds configuration for the Jenkins pipeline strategy
... ...
@@ -73,6 +73,15 @@ func (AssetExtensionsConfig) SwaggerDoc() map[string]string {
73 73
 	return map_AssetExtensionsConfig
74 74
 }
75 75
 
76
+var map_AuditConfig = map[string]string{
77
+	"":        "AuditConfig holds configuration for the audit capabilities",
78
+	"enabled": "If this flag is set, basic audit log will be printed in the logs. The logs contains, method, user and a requested URL.",
79
+}
80
+
81
+func (AuditConfig) SwaggerDoc() map[string]string {
82
+	return map_AuditConfig
83
+}
84
+
76 85
 var map_AugmentedActiveDirectoryConfig = map[string]string{
77 86
 	"":                          "AugmentedActiveDirectoryConfig holds the necessary configuration options to define how an LDAP group sync interacts with an LDAP server using the augmented Active Directory schema",
78 87
 	"usersQuery":                "AllUsersQuery holds the template for an LDAP query that returns user entries.",
... ...
@@ -433,6 +442,7 @@ var map_MasterConfig = map[string]string{
433 433
 	"networkConfig":          "NetworkConfig to be passed to the compiled in network plugin",
434 434
 	"volumeConfig":           "MasterVolumeConfig contains options for configuring volume plugins in the master node.",
435 435
 	"jenkinsPipelineConfig":  "JenkinsPipelineConfig holds information about the default Jenkins template used for JenkinsPipeline build strategy.",
436
+	"auditConfig":            "AuditConfig holds information related to auditing capabilities.",
436 437
 }
437 438
 
438 439
 func (MasterConfig) SwaggerDoc() map[string]string {
... ...
@@ -235,6 +235,16 @@ type MasterConfig struct {
235 235
 	// JenkinsPipelineConfig holds information about the default Jenkins template
236 236
 	// used for JenkinsPipeline build strategy.
237 237
 	JenkinsPipelineConfig JenkinsPipelineConfig `json:"jenkinsPipelineConfig"`
238
+
239
+	// AuditConfig holds information related to auditing capabilities.
240
+	AuditConfig AuditConfig `json:"auditConfig"`
241
+}
242
+
243
+// AuditConfig holds configuration for the audit capabilities
244
+type AuditConfig struct {
245
+	// If this flag is set, basic audit log will be printed in the logs.
246
+	// The logs contains, method, user and a requested URL.
247
+	Enabled bool `json:"enabled"`
238 248
 }
239 249
 
240 250
 // JenkinsPipelineConfig holds configuration for the Jenkins pipeline strategy
... ...
@@ -102,6 +102,8 @@ assetConfig:
102 102
     maxRequestsInFlight: 0
103 103
     namedCertificates: null
104 104
     requestTimeoutSeconds: 0
105
+auditConfig:
106
+  enabled: false
105 107
 controllerConfig:
106 108
   serviceServingCert:
107 109
     signer: null
108 110
new file mode 100644
... ...
@@ -0,0 +1,58 @@
0
+package origin
1
+
2
+import (
3
+	"net/http"
4
+
5
+	"github.com/golang/glog"
6
+	"github.com/pborman/uuid"
7
+
8
+	kapi "k8s.io/kubernetes/pkg/api"
9
+	"k8s.io/kubernetes/pkg/util/net"
10
+
11
+	authenticationapi "github.com/openshift/origin/pkg/auth/api"
12
+)
13
+
14
+type auditResponseWriter struct {
15
+	http.ResponseWriter
16
+	id string
17
+}
18
+
19
+func (a *auditResponseWriter) WriteHeader(code int) {
20
+	glog.Infof("AUDIT: id=%q response=\"%d\"", a.id, code)
21
+	a.ResponseWriter.WriteHeader(code)
22
+}
23
+
24
+// auditHandler is responsible for logging audit information for all the
25
+// request coming to server. Each audit log contains two entries:
26
+// 1. the request line containing:
27
+//    - unique id allowing to match the response line (see 2)
28
+//    - source ip of the request
29
+//    - HTTP method being invoked
30
+//    - original user invoking the operation
31
+//    - impersonated user for the operation
32
+//    - namespace of the request or <none>
33
+//    - uri is the full URI as requested
34
+// 2. the response line containing the unique id from 1 and response code
35
+func (c *MasterConfig) auditHandler(handler http.Handler) http.Handler {
36
+	if !c.Options.AuditConfig.Enabled {
37
+		return handler
38
+	}
39
+
40
+	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
41
+		ctx, _ := c.RequestContextMapper.Get(req)
42
+		user, _ := kapi.UserFrom(ctx)
43
+		asuser := req.Header.Get(authenticationapi.ImpersonateUserHeader)
44
+		if len(asuser) == 0 {
45
+			asuser = "<self>"
46
+		}
47
+		namespace := kapi.NamespaceValue(ctx)
48
+		if len(namespace) == 0 {
49
+			namespace = "<none>"
50
+		}
51
+		id := uuid.NewRandom().String()
52
+
53
+		glog.Infof("AUDIT: id=%q ip=%q method=%q user=%q as=%q namespace=%q uri=%q",
54
+			id, net.GetClientIP(req), req.Method, user.GetName(), asuser, namespace, req.URL)
55
+		handler.ServeHTTP(&auditResponseWriter{w, id}, req)
56
+	})
57
+}
... ...
@@ -164,6 +164,8 @@ func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller)
164 164
 	handler := c.versionSkewFilter(safe)
165 165
 	handler = c.authorizationFilter(handler)
166 166
 	handler = c.impersonationFilter(handler)
167
+	// audit handler must comes before the impersonationFilter to read the original user
168
+	handler = c.auditHandler(handler)
167 169
 	handler = authenticationHandlerFilter(handler, c.Authenticator, c.getRequestContextMapper())
168 170
 	handler = namespacingFilter(handler, c.getRequestContextMapper())
169 171
 	handler = cacheControlFilter(handler, "no-store") // protected endpoints should not be cached