Skip to content

Commit

Permalink
Basic audit extended test
Browse files Browse the repository at this point in the history
  • Loading branch information
soltysh committed Sep 21, 2017
1 parent 49ef6df commit e8e6700
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 3 deletions.
150 changes: 150 additions & 0 deletions test/extended/cluster/audit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package cluster

import (
"bufio"
"fmt"
"os"
"path/filepath"
"strings"

g "github.com/onsi/ginkgo"
o "github.com/onsi/gomega"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
apiv1 "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/test/e2e/framework"
)

var _ = g.Describe("[Feature:Audit] Basic audit", func() {
f := framework.NewDefaultFramework("audit")

g.It("should audit API calls", func() {
namespace := f.Namespace.Name

// Create & Delete pod
pod := &apiv1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "audit-pod",
},
Spec: apiv1.PodSpec{
Containers: []apiv1.Container{{
Name: "pause",
Image: framework.GetPauseImageName(f.ClientSet),
}},
},
}
f.PodClient().CreateSync(pod)
f.PodClient().DeleteSync(pod.Name, &metav1.DeleteOptions{}, framework.DefaultPodDeletionTimeout)

// Create, Read, Delete secret
secret := &apiv1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "audit-secret",
},
Data: map[string][]byte{
"top-secret": []byte("foo-bar"),
},
}
_, err := f.ClientSet.Core().Secrets(f.Namespace.Name).Create(secret)
framework.ExpectNoError(err, "failed to create audit-secret")
_, err = f.ClientSet.Core().Secrets(f.Namespace.Name).Get(secret.Name, metav1.GetOptions{})
framework.ExpectNoError(err, "failed to get audit-secret")
err = f.ClientSet.Core().Secrets(f.Namespace.Name).Delete(secret.Name, &metav1.DeleteOptions{})
framework.ExpectNoError(err, "failed to delete audit-secret")

// /version should not be audited
_, err = f.ClientSet.Core().RESTClient().Get().AbsPath("/version").DoRaw()
framework.ExpectNoError(err, "failed to query version")

expectedEvents := []auditEvent{{
method: "create",
namespace: namespace,
uri: fmt.Sprintf("/api/v1/namespaces/%s/pods", namespace),
response: "201",
}, {
method: "delete",
namespace: namespace,
uri: fmt.Sprintf("/api/v1/namespaces/%s/pods/%s", namespace, pod.Name),
response: "200",
}, {
method: "create",
namespace: namespace,
uri: fmt.Sprintf("/api/v1/namespaces/%s/secrets", namespace),
response: "201",
}, {
method: "get",
namespace: namespace,
uri: fmt.Sprintf("/api/v1/namespaces/%s/secrets/%s", namespace, secret.Name),
response: "200",
}, {
method: "delete",
namespace: namespace,
uri: fmt.Sprintf("/api/v1/namespaces/%s/secrets/%s", namespace, secret.Name),
response: "200",
}}
expectAuditLines(f, expectedEvents)
})
})

type auditEvent struct {
method, namespace, uri, response string
}

// Search the audit log for the expected audit lines.
func expectAuditLines(f *framework.Framework, expected []auditEvent) {
expectations := map[auditEvent]bool{}
for _, event := range expected {
expectations[event] = false
}

stream, err := os.Open(filepath.Join(os.Getenv("LOG_DIR"), "audit.log"))
defer stream.Close()
framework.ExpectNoError(err, "error opening audit log")
scanner := bufio.NewScanner(stream)
for scanner.Scan() {
line := scanner.Text()
event, err := parseAuditLine(line)
framework.ExpectNoError(err)

// If the event was expected, mark it as found.
if _, found := expectations[event]; found {
expectations[event] = true
}
}
framework.ExpectNoError(scanner.Err(), "error reading audit log")

for event, found := range expectations {
o.Expect(found).To(o.BeTrue(), "Event %#v not found!", event)
}
}

func parseAuditLine(line string) (auditEvent, error) {
fields := strings.Fields(line)
if len(fields) < 3 {
return auditEvent{}, fmt.Errorf("could not parse audit line: %s", line)
}
// Ignore first field (timestamp)
if fields[1] != "AUDIT:" {
return auditEvent{}, fmt.Errorf("unexpected audit line format: %s", line)
}
fields = fields[2:]
event := auditEvent{}
for _, f := range fields {
parts := strings.SplitN(f, "=", 2)
if len(parts) != 2 {
return auditEvent{}, fmt.Errorf("could not parse audit line (part: %q): %s", f, line)
}
value := strings.Trim(parts[1], "\"")
switch parts[0] {
case "method":
event.method = value
case "namespace":
event.namespace = value
case "uri":
event.uri = value
case "response":
event.response = value
}
}
return event, nil
}
7 changes: 4 additions & 3 deletions test/extended/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function os::test::extended::focus () {
TEST_REPORT_FILE_NAME=focus_parallel TEST_PARALLEL="${PARALLEL_NODES:-5}" os::test::extended::run -- -ginkgo.skip "\[Serial\]" -test.timeout 6h ${TEST_EXTENDED_ARGS-} || exitstatus=$?

# Then run everything that requires serial and matches the $FOCUS, serially.
# there is bit of overlap here because not all serial tests declare [Serial], so they might have run in the
# there is bit of overlap here because not all serial tests declare [Serial], so they might have run in the
# parallel section above. Hopefully your focus was precise enough to exclude them, and we should be adding
# the [Serial] tag to them as needed.
os::log::info ""
Expand Down Expand Up @@ -110,11 +110,12 @@ function os::test::extended::setup () {
CONFIG_VERSION="${CONTROLLER_VERSION}"
fi
os::start::configure_server "${CONFIG_VERSION}"
#turn on audit logging for extended tests ... mimic what is done in os::start::configure_server, but don't
# turn on audit logging for extended tests ... mimic what is done in os::start::configure_server, but don't
# put change there - only want this for extended tests
os::log::info "Turn on audit logging"
cp "${SERVER_CONFIG_DIR}/master/master-config.yaml" "${SERVER_CONFIG_DIR}/master/master-config.orig2.yaml"
openshift ex config patch "${SERVER_CONFIG_DIR}/master/master-config.orig2.yaml" --patch="{\"auditConfig\": {\"enabled\": true}}" > "${SERVER_CONFIG_DIR}/master/master-config.yaml"
openshift ex config patch "${SERVER_CONFIG_DIR}/master/master-config.orig2.yaml" --patch="{\"auditConfig\": {\"enabled\": true, \"auditFilePath\": \"${LOG_DIR}/audit.log\"}}" > "${SERVER_CONFIG_DIR}/master/master-config.yaml"
exit 1

cp "${SERVER_CONFIG_DIR}/master/master-config.yaml" "${SERVER_CONFIG_DIR}/master/master-config.orig2.yaml"
openshift ex config patch "${SERVER_CONFIG_DIR}/master/master-config.orig2.yaml" --patch="{\"templateServiceBrokerConfig\": {\"templateNamespaces\": [\"openshift\"]}}" > "${SERVER_CONFIG_DIR}/master/master-config.yaml"
Expand Down

0 comments on commit e8e6700

Please sign in to comment.