Repository: zegl/kube-score (go)

Issue:
check for nodeport usage in service is missing
**Describe the bug**
We'd like to prevent usage of nodeport in our services. Currently there is no check for this.

Reason: https://oteemo.com/2017/12/12/think-nodeport-kubernetes/

**To Reproduce**

```
Insert a YAML document that triggers the incorrect behaviour
```

**Expected behavior**
A clear and concise description of what you expected to happen.

**Version**
kube-score version: [e.g. 0.3.0]


**Additional context**
Add any other context about the problem here.


Pull request:
service: advice against use of nodeport services
Fixes #64

Patch:
diff --git a/score/score.go b/score/score.go
index 1c37e75..3268006 100644
--- a/score/score.go
+++ b/score/score.go
@@ -243,6 +243,7 @@ func (s *score) runTests() (*scorecard.Scorecard, error) {
 
 	serviceTests := []func(corev1.Service) scorecard.TestScore{
 		service.ScoreServiceTargetsPod(s.pods, s.podspecers),
+		service.ScoreServiceType,
 	}
 
 	statefulSetTests := []func(appsv1.StatefulSet) scorecard.TestScore{
diff --git a/score/service/service.go b/score/service/service.go
index 950b8d3..88c68ee 100644
--- a/score/service/service.go
+++ b/score/service/service.go
@@ -57,3 +57,17 @@ func ScoreServiceTargetsPod(pods []corev1.Pod, podspecers []ks.PodSpecer) func(c
 		return
 	}
 }
+
+func ScoreServiceType(service corev1.Service) (score scorecard.TestScore) {
+	score.Name = "Service Type"
+	score.ID = "service-type"
+
+	if service.Spec.Type == corev1.ServiceTypeNodePort {
+		score.Grade = scorecard.GradeWarning
+		score.AddComment("", "The service is of type NodePort", "NodePort services should be avoided as they are insecure, and can not be used together with NetworkPolicies. LoadBalancers or use of an Ingress is recommended over NodePorts.")
+		return
+	}
+
+	score.Grade = scorecard.GradeAllOK
+	return
+}


Test patch:
diff --git a/score/service_test.go b/score/service_test.go
index bb971e0..8cd292c 100644
--- a/score/service_test.go
+++ b/score/service_test.go
@@ -45,3 +45,15 @@ func TestServiceTargetsPodDeploymentDifferentNamespace(t *testing.T) {
 func TestServiceExternalName(t *testing.T) {
 	testExpectedScore(t, "service-externalname.yaml", "Service Targets Pod", 10)
 }
+
+func TestServiceTypeNodePort(t *testing.T) {
+	testExpectedScore(t, "service-type-nodeport.yaml", "Service Type", 5)
+}
+
+func TestServiceTypeClusterIP(t *testing.T) {
+	testExpectedScore(t, "service-type-clusterip.yaml", "Service Type", 10)
+}
+
+func TestServiceTypeDefault(t *testing.T) {
+	testExpectedScore(t, "service-type-default.yaml", "Service Type", 10)
+}
diff --git a/score/testdata/service-type-clusterip.yaml b/score/testdata/service-type-clusterip.yaml
new file mode 100644
index 0000000..92ee73d
--- /dev/null
+++ b/score/testdata/service-type-clusterip.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: node-port-service
+  namespace: foospace
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
+  type: ClusterIP
diff --git a/score/testdata/service-type-default.yaml b/score/testdata/service-type-default.yaml
new file mode 100644
index 0000000..b8260a5
--- /dev/null
+++ b/score/testdata/service-type-default.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: node-port-service
+  namespace: foospace
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-type-nodeport.yaml b/score/testdata/service-type-nodeport.yaml
new file mode 100644
index 0000000..bf099c2
--- /dev/null
+++ b/score/testdata/service-type-nodeport.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: node-port-service
+  namespace: foospace
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
+  type: NodePort