Skip to content

Commit

Permalink
add pod host networking validations
Browse files Browse the repository at this point in the history
  • Loading branch information
JessicaGreben committed Feb 13, 2019
1 parent 5f7130d commit 16409c0
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 31 deletions.
11 changes: 11 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,14 @@ images:
tagRequired: true
whitelistRepos:
- gcr.io
hostNetwork:
hostAlias:
require: true
hostIPC:
require: true
hostNetwork:
require: true
hostPID:
require: true
hostPort:
require: true
11 changes: 11 additions & 0 deletions deploy/all.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ data:
tagRequired: true
whitelistRepos:
- gcr.io
hostNetwork:
hostAlias:
require: true
hostIPC:
require: true
hostNetwork:
require: true
hostPID:
require: true
hostPort:
require: true
---
apiVersion: extensions/v1beta1
kind: Deployment
Expand Down
6 changes: 5 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ type Images struct {

// HostNetwork contains the config for host networking validations.
type HostNetwork struct {
HostPort bool `json:"hostPort"`
HostAlias ResourceRequire `json:"hostAlias"`
HostIPC ResourceRequire `json:"hostIPC"`
HostNetwork ResourceRequire `json:"hostNetwork"`
HostPID ResourceRequire `json:"hostPID"`
HostPort ResourceRequire `json:"hostPort"`
}

// ParseFile parses config from a file.
Expand Down
36 changes: 23 additions & 13 deletions pkg/dashboard/templates/dashboard.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,32 @@
{{ range $namespace, $results := .NamespacedResults }}
<div class="namespace">
<h3>Namespace: <strong>{{ $namespace }}</strong></h3>

<table class="namespace-content" cellspacing="0">
{{ range $results.Results }}
<tr>
<td class="resource-info">
<div class="name"><span class="caret-expander"></span>{{ .Type }}: <strong>{{ .Name }}</strong></div>
{{ range .ContainerResults}}
<div class="extra">
<h4>{{ .Name }}</h4>
<ul>
{{ range .Messages}}
<li class="{{ .Type }}"><span>&#{{ .HTMLSpecialCharCode }};</span> {{ .Message }}</li>
{{ end }}
</ul>
</div>
{{ end }}

{{ range .PodResults}}
<div class="extra">
<h4>Pod:</h4>
<ul>
{{ range .Messages}}
<li class="{{ .Type }}"><span>&#{{ .HTMLSpecialCharCode }};</span> {{ .Message }}</li>
{{ end }}
</ul>
</div>
{{ range .ContainerResults}}
<div class="extra">
<h4>Container: {{ .Name }}</h4>
<ul>
{{ range .Messages}}
<li class="{{ .Type }}"><span>&#{{ .HTMLSpecialCharCode }};</span> {{ .Message }}</li>
{{ end }}
</ul>
</div>
{{ end }} {{/* end range .ContainerResults */}}
{{ end }} {{/* end range .PodResults */}}
</td>
<td class="status-bar">
<div class="status">
Expand All @@ -70,10 +80,10 @@
</div>
</td>
</tr>
{{ end }}
{{ end }} {{/* end range .Results */}}
</table>
</div>
{{ end }}
{{ end }} {{/* end range .NamespacedResults */}}
</div>

<script>
Expand Down
6 changes: 3 additions & 3 deletions pkg/validator/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,13 @@ func (cv *ContainerValidation) validateImage(conf conf.Images) {
}

func (cv *ContainerValidation) validateHostPort(conf conf.HostNetwork) {
if conf.HostPort {
if conf.HostPort.Require {
for _, port := range cv.Container.Ports {
if port.HostPort != 0 {
cv.addFailure("Host port should not be configured")
cv.addFailure("Host port is configured, but it shouldn't be")
return
}
}
cv.addSuccess("Host port is not configured")
cv.addSuccess("Host port should not be configured")
}
}
129 changes: 115 additions & 14 deletions pkg/validator/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,137 @@ import (

var log = logf.Log.WithName("Fairwinds Validator")

// PodValidation tracks validation failures associated with a Pod.
type PodValidation struct {
Pod corev1.PodSpec
Summary ResultSummary
Failures []ResultMessage
Warnings []ResultMessage
Successes []ResultMessage
}

func (pv *PodValidation) messages() []ResultMessage {
mssgs := []ResultMessage{}
mssgs = append(mssgs, pv.Failures...)
mssgs = append(mssgs, pv.Warnings...)
mssgs = append(mssgs, pv.Successes...)
return mssgs
}

// ValidatePod validates that each pod conforms to the Fairwinds config, returns a ResourceResult.
func ValidatePod(conf conf.Configuration, pod *corev1.PodSpec) ResourceResult {
resResult := ResourceResult{
Type: "Pod",
Summary: &ResultSummary{},
pv := PodValidation{
Pod: *pod,
Summary: ResultSummary{},
}

pv.validateHostNetwork(conf.HostNetwork)

pRes := PodResult{
Messages: pv.messages(),
ContainerResults: []ContainerResult{},
}

// Add container resource results to the pod resource results.
for _, container := range pod.InitContainers {
ctrRR := validateContainer(conf, container)
resResult.Summary.Successes += ctrRR.Summary.Successes
resResult.Summary.Warnings += ctrRR.Summary.Warnings
resResult.Summary.Failures += ctrRR.Summary.Failures
resResult.ContainerResults = append(
resResult.ContainerResults,
pv.Summary.Successes += ctrRR.Summary.Successes
pv.Summary.Warnings += ctrRR.Summary.Warnings
pv.Summary.Failures += ctrRR.Summary.Failures
pRes.ContainerResults = append(
pRes.ContainerResults,
ctrRR.ContainerResults[0],
)
}

for _, container := range pod.Containers {
ctrRR := validateContainer(conf, container)
resResult.Summary.Successes += ctrRR.Summary.Successes
resResult.Summary.Warnings += ctrRR.Summary.Warnings
resResult.Summary.Failures += ctrRR.Summary.Failures
resResult.ContainerResults = append(
resResult.ContainerResults,
pv.Summary.Successes += ctrRR.Summary.Successes
pv.Summary.Warnings += ctrRR.Summary.Warnings
pv.Summary.Failures += ctrRR.Summary.Failures
pRes.ContainerResults = append(
pRes.ContainerResults,
ctrRR.ContainerResults[0],
)
}
rr := ResourceResult{
Type: "Pod",
Summary: &pv.Summary,
PodResults: []PodResult{pRes},
}

return rr
}

func (pv *PodValidation) addFailure(message string) {
pv.Summary.Failures++
pv.Failures = append(pv.Failures, ResultMessage{
Message: message,
Type: "failure",
})
}

func (pv *PodValidation) addWarning(message string) {
pv.Summary.Warnings++
pv.Warnings = append(pv.Warnings, ResultMessage{
Message: message,
Type: "warning",
})
}

func (pv *PodValidation) addSuccess(message string) {
pv.Summary.Successes++
pv.Successes = append(pv.Successes, ResultMessage{
Message: message,
Type: "success",
})
}

func (pv *PodValidation) validateHostNetwork(conf conf.HostNetwork) {
pv.hostAlias(conf)
pv.hostIPC(conf)
pv.hostPID(conf)
pv.hostNetwork(conf)
}

func (pv *PodValidation) hostAlias(conf conf.HostNetwork) {
if conf.HostAlias.Require {
for _, alias := range pv.Pod.HostAliases {
if alias.IP != "" && len(alias.Hostnames) == 0 {
pv.addFailure("Host alias should is configured, but it shouldn't be")
return
}
}
pv.addSuccess("Host alias should not be configured")
}
}

func (pv *PodValidation) hostIPC(conf conf.HostNetwork) {
if conf.HostIPC.Require {
if pv.Pod.HostIPC {
pv.addFailure("Host IPC is configured, but it shouldn't be")
return
}
pv.addSuccess("Host IPC should not be configured")
}
}

return resResult
func (pv *PodValidation) hostPID(conf conf.HostNetwork) {
if conf.HostPID.Require {
if pv.Pod.HostPID {
pv.addFailure("Host PID is configured, but it shouldn't be")
return
}
pv.addSuccess("Host PID should not be configured")
}
}

func (pv *PodValidation) hostNetwork(conf conf.HostNetwork) {
if conf.HostNetwork.Require {
if pv.Pod.HostNetwork {
pv.addFailure("Host network is configured, but it shouldn't be")
return
}
pv.addSuccess("Host network sould not be configured")
}
}
8 changes: 8 additions & 0 deletions pkg/validator/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type ResourceResult struct {
Type string
Summary *ResultSummary
ContainerResults []ContainerResult
PodResults []PodResult
}

// ResultSummary provides a high level overview of success, warnings, and failures.
Expand All @@ -30,6 +31,13 @@ type ContainerResult struct {
Messages []ResultMessage
}

// PodResult provides a list of validation messages for each pod.
type PodResult struct {
Name string
Messages []ResultMessage
ContainerResults []ContainerResult
}

// ResultMessage contains a message and a type indicator (success, warning, or failure).
type ResultMessage struct {
Message string
Expand Down
5 changes: 5 additions & 0 deletions test/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ spec:
labels:
app: nginx
spec:
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "foo.local"
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
- hostPort: 80

0 comments on commit 16409c0

Please sign in to comment.