Skip to content

Commit 2606318

Browse files
weixiongnytrumantmdb
authored
Add support to check dnsConfig options (#358)
Co-authored-by: Travis Truman <[email protected]> Co-authored-by: Mike Ball <[email protected]>
1 parent 43c3d24 commit 2606318

File tree

10 files changed

+490
-0
lines changed

10 files changed

+490
-0
lines changed

docs/generated/checks.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,22 @@ serviceAccount: ^(|default)$
118118
**Remediation**: Use the serviceAccountName field instead. If you must specify serviceAccount, ensure values for serviceAccount and serviceAccountName match.
119119
120120
**Template**: [deprecated-service-account-field](generated/templates.md#deprecated-service-account-field)
121+
## dnsconfig-options
122+
123+
**Enabled by default**: No
124+
125+
**Description**: Alert on deployments that have no specified dnsConfig options
126+
127+
**Remediation**: Specify dnsconfig options in your Pod specification to ensure the expected DNS setting on the Pod. Refer to https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config for details.
128+
129+
**Template**: [dnsconfig-options](generated/templates.md#dnsconfig-options)
130+
131+
**Parameters**:
132+
133+
```yaml
134+
Key: ndots
135+
Value: "2"
136+
```
121137
## docker-sock
122138
123139
**Enabled by default**: Yes

docs/generated/templates.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,32 @@ KubeLinter supports the following templates:
187187
type: string
188188
```
189189

190+
## DnsConfig Options
191+
192+
**Key**: `dnsconfig-options`
193+
194+
**Description**: Flag objects that don't have specified DNSConfig Options
195+
196+
**Supported Objects**: DeploymentLike
197+
198+
199+
**Parameters**:
200+
201+
```yaml
202+
- description: Key of the dnsConfig option.
203+
name: key
204+
negationAllowed: true
205+
regexAllowed: true
206+
required: false
207+
type: string
208+
- description: Value of the dnsConfig option.
209+
name: value
210+
negationAllowed: true
211+
regexAllowed: true
212+
required: false
213+
type: string
214+
```
215+
190216
## Environment Variables
191217

192218
**Key**: `env-var`

e2etests/bats-tests.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,25 @@ get_value_from() {
162162
[[ "${count}" == "2" ]]
163163
}
164164

165+
@test "dnsconfig-options" {
166+
tmp="tests/checks/dnsconfig-options-ndots.yml"
167+
cmd="${KUBE_LINTER_BIN} lint --include dnsconfig-options --do-not-auto-add-defaults --format json ${tmp}"
168+
run ${cmd}
169+
170+
print_info "${status}" "${output}" "${cmd}" "${tmp}"
171+
[ "$status" -eq 1 ]
172+
173+
message1=$(get_value_from "${lines[0]}" '.Reports[0].Object.K8sObject.GroupVersionKind.Kind + ": " + .Reports[0].Diagnostic.Message')
174+
message2=$(get_value_from "${lines[0]}" '.Reports[1].Object.K8sObject.GroupVersionKind.Kind + ": " + .Reports[1].Diagnostic.Message')
175+
message3=$(get_value_from "${lines[0]}" '.Reports[2].Object.K8sObject.GroupVersionKind.Kind + ": " + .Reports[2].Diagnostic.Message')
176+
count=$(get_value_from "${lines[0]}" '.Reports | length')
177+
178+
[[ "${message1}" == "Deployment: DNSConfig Options \"ndots:2\" not found." ]]
179+
[[ "${message2}" == "Deployment: Object does not define any DNSConfig Options." ]]
180+
[[ "${message3}" == "Deployment: Object does not define any DNSConfig rules." ]]
181+
[[ "${count}" == "3" ]]
182+
}
183+
165184
@test "docker-sock" {
166185
tmp="tests/checks/docker-sock.yml"
167186
cmd="${KUBE_LINTER_BIN} lint --include docker-sock --do-not-auto-add-defaults --format json ${tmp}"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: "dnsconfig-options"
2+
description: "Alert on deployments that have no specified dnsConfig options"
3+
remediation: >-
4+
Specify dnsconfig options in your Pod specification to ensure the expected DNS setting on the Pod.
5+
Refer to https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config for details.
6+
scope:
7+
objectKinds:
8+
- DeploymentLike
9+
template: "dnsconfig-options"
10+
params:
11+
Key: ndots
12+
Value: "2"

pkg/templates/all/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
_ "golang.stackrox.io/kube-linter/pkg/templates/danglingservice"
1414
_ "golang.stackrox.io/kube-linter/pkg/templates/deprecatedserviceaccount"
1515
_ "golang.stackrox.io/kube-linter/pkg/templates/disallowedgvk"
16+
_ "golang.stackrox.io/kube-linter/pkg/templates/dnsconfigoptions"
1617
_ "golang.stackrox.io/kube-linter/pkg/templates/envvar"
1718
_ "golang.stackrox.io/kube-linter/pkg/templates/forbiddenannotation"
1819
_ "golang.stackrox.io/kube-linter/pkg/templates/hostipc"

pkg/templates/dnsconfigoptions/internal/params/gen-params.go

Lines changed: 86 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package params
2+
3+
// Params represents the params accepted by this template.
4+
type Params struct {
5+
6+
// Key of the dnsConfig option.
7+
Key string
8+
9+
// Value of the dnsConfig option.
10+
Value string
11+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package dnsconfigoptions
2+
3+
import (
4+
"fmt"
5+
6+
"golang.stackrox.io/kube-linter/pkg/check"
7+
"golang.stackrox.io/kube-linter/pkg/config"
8+
"golang.stackrox.io/kube-linter/pkg/diagnostic"
9+
"golang.stackrox.io/kube-linter/pkg/extract"
10+
"golang.stackrox.io/kube-linter/pkg/lintcontext"
11+
"golang.stackrox.io/kube-linter/pkg/objectkinds"
12+
"golang.stackrox.io/kube-linter/pkg/templates"
13+
"golang.stackrox.io/kube-linter/pkg/templates/dnsconfigoptions/internal/params"
14+
)
15+
16+
func init() {
17+
templates.Register(check.Template{
18+
HumanName: "DnsConfig Options",
19+
Key: "dnsconfig-options",
20+
Description: "Flag objects that don't have specified DNSConfig Options",
21+
SupportedObjectKinds: config.ObjectKindsDesc{
22+
ObjectKinds: []string{objectkinds.DeploymentLike},
23+
},
24+
Parameters: params.ParamDescs,
25+
ParseAndValidateParams: params.ParseAndValidate,
26+
Instantiate: params.WrapInstantiateFunc(func(p params.Params) (check.Func, error) {
27+
return func(_ lintcontext.LintContext, object lintcontext.Object) []diagnostic.Diagnostic {
28+
podTemplateSpec, found := extract.PodTemplateSpec(object.K8sObject)
29+
if !found {
30+
return nil
31+
}
32+
if podTemplateSpec.Spec.DNSConfig == nil {
33+
return []diagnostic.Diagnostic{{Message: "Object does not define any DNSConfig rules."}}
34+
}
35+
if podTemplateSpec.Spec.DNSConfig.Options == nil {
36+
return []diagnostic.Diagnostic{{Message: "Object does not define any DNSConfig Options."}}
37+
}
38+
39+
for _, option := range podTemplateSpec.Spec.DNSConfig.Options {
40+
if option.Name == p.Key && *option.Value == p.Value {
41+
// Found
42+
return nil
43+
}
44+
}
45+
return []diagnostic.Diagnostic{{
46+
Message: fmt.Sprintf("DNSConfig Options \"%s:%s\" not found.", p.Key, p.Value),
47+
}}
48+
}, nil
49+
}),
50+
})
51+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package dnsconfigoptions
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/stretchr/testify/suite"
8+
"golang.stackrox.io/kube-linter/pkg/diagnostic"
9+
"golang.stackrox.io/kube-linter/pkg/lintcontext/mocks"
10+
"golang.stackrox.io/kube-linter/pkg/templates"
11+
"golang.stackrox.io/kube-linter/pkg/templates/dnsconfigoptions/internal/params"
12+
appsV1 "k8s.io/api/apps/v1"
13+
v1 "k8s.io/api/core/v1"
14+
)
15+
16+
func TestDnsconfigOptions(t *testing.T) {
17+
suite.Run(t, new(DnsconfigOptionsTestSuite))
18+
}
19+
20+
type DnsconfigOptionsTestSuite struct {
21+
templates.TemplateTestSuite
22+
ctx *mocks.MockLintContext
23+
}
24+
25+
const (
26+
templateKey = "dnsconfig-options"
27+
deploymentName = "deployment"
28+
key = "ndots"
29+
value = "2"
30+
)
31+
32+
func (s *DnsconfigOptionsTestSuite) SetupTest() {
33+
s.Init(templateKey)
34+
s.ctx = mocks.NewMockContext()
35+
}
36+
37+
func (s *DnsconfigOptionsTestSuite) TestIgnoreDnsconfigOptionsCheckOnObjectWithoutDnsconfig() {
38+
s.ctx.AddMockClusterRole(s.T(), deploymentName)
39+
s.Validate(s.ctx, []templates.TestCase{
40+
{
41+
Param: params.Params{Key: key, Value: value},
42+
Diagnostics: nil,
43+
ExpectInstantiationError: false,
44+
},
45+
})
46+
}
47+
48+
func (s *DnsconfigOptionsTestSuite) TestNoPodTemplateSpecDnsconfigDefined() {
49+
s.ctx.AddMockDeployment(s.T(), deploymentName)
50+
51+
s.Validate(s.ctx, []templates.TestCase{
52+
{
53+
Param: params.Params{Key: key, Value: value},
54+
Diagnostics: map[string][]diagnostic.Diagnostic{
55+
deploymentName: {
56+
{
57+
Message: "Object does not define any DNSConfig rules.",
58+
},
59+
},
60+
},
61+
ExpectInstantiationError: false,
62+
},
63+
})
64+
}
65+
66+
func (s *DnsconfigOptionsTestSuite) TestNoDnsconfigOptionsDefined() {
67+
s.ctx.AddMockDeployment(s.T(), deploymentName)
68+
69+
s.ctx.ModifyDeployment(s.T(), deploymentName, func(deployment *appsV1.Deployment) {
70+
dnsconfig := &v1.PodDNSConfig{
71+
Options: nil,
72+
}
73+
deployment.Spec.Template.Spec.DNSConfig = dnsconfig
74+
})
75+
76+
s.Validate(s.ctx, []templates.TestCase{
77+
{
78+
Param: params.Params{Key: key, Value: value},
79+
Diagnostics: map[string][]diagnostic.Diagnostic{
80+
deploymentName: {
81+
{
82+
Message: "Object does not define any DNSConfig Options.",
83+
},
84+
},
85+
},
86+
ExpectInstantiationError: false,
87+
},
88+
})
89+
}
90+
91+
func (s *DnsconfigOptionsTestSuite) TestDnsconfigOptionsNotMatched() {
92+
s.ctx.AddMockDeployment(s.T(), deploymentName)
93+
94+
v := "5"
95+
s.ctx.ModifyDeployment(s.T(), deploymentName, func(deployment *appsV1.Deployment) {
96+
dnsconfig := &v1.PodDNSConfig{
97+
Options: []v1.PodDNSConfigOption{
98+
{
99+
Name: "foo",
100+
Value: &v,
101+
},
102+
},
103+
}
104+
deployment.Spec.Template.Spec.DNSConfig = dnsconfig
105+
})
106+
107+
s.Validate(s.ctx, []templates.TestCase{
108+
{
109+
Param: params.Params{Key: key, Value: value},
110+
Diagnostics: map[string][]diagnostic.Diagnostic{
111+
deploymentName: {
112+
{
113+
Message: fmt.Sprintf("DNSConfig Options \"%s:%s\" not found.", key, value),
114+
},
115+
},
116+
},
117+
ExpectInstantiationError: false,
118+
},
119+
})
120+
}
121+
122+
func (s *DnsconfigOptionsTestSuite) TestDnsconfigOptionsMatched() {
123+
s.ctx.AddMockDeployment(s.T(), deploymentName)
124+
125+
v := "2"
126+
s.ctx.ModifyDeployment(s.T(), deploymentName, func(deployment *appsV1.Deployment) {
127+
dnsconfig := &v1.PodDNSConfig{
128+
Options: []v1.PodDNSConfigOption{
129+
{
130+
Name: "ndots",
131+
Value: &v,
132+
},
133+
},
134+
}
135+
deployment.Spec.Template.Spec.DNSConfig = dnsconfig
136+
})
137+
138+
s.Validate(s.ctx, []templates.TestCase{
139+
{
140+
Param: params.Params{Key: key, Value: value},
141+
Diagnostics: nil,
142+
ExpectInstantiationError: false,
143+
},
144+
})
145+
}

0 commit comments

Comments
 (0)