| ... | ... |
@@ -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 |
| 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 |