Repository: kinvolk/lokomotive
Pull request #468 (2020-05-21 11:20:10)

Add variable `grafana_ingress_host` to expose Grafana
Fixes: https://github.com/kinvolk/lokomotive/issues/456

johananl: ```
TestAWSIngress: aws_test.go:49: got an HTTP error: Get "https://httpbin.ci1590498787-sj.test.lokomotive-k8s.net/get": dial tcp 3.121.121.100:443: connect: connection refused
    TestAWSIngress: aws_test.go:67: could not get a successful HTTP response in time
```
surajssd: So it was decided in a meeting that we create block for grafana like this:

```tf
component "prometheus-operator" {
...
  grafana {
    admin_password = ""

    ingress {
      host = ""

      # In future
      ingress_class = ""
      certmanager_cluster_issuer = ""
    }
  }
}
```
surajssd: > Overall LGTM, but I don't understand, why do we remove Grafana admin password. @surajssd please add some explanation to it, so we can discuss it.

Grafana admin password should not be a compulsory option. If not provided the chart automatically creates one for you, just like Rook Ceph.
invidian: >Grafana admin password should not be a compulsory option. If not provided the chart automatically creates one for you, just like Rook Ceph.

Hm, okay. I think we should have a bit more documentation how to obtain this password then, so it is not so cryptic to the users.
surajssd: > Hm, okay. I think we should have a bit more documentation how to obtain this password then, so it is not so cryptic to the users.

That I plan to handle as a part of https://github.com/kinvolk/lokomotive/pull/480
iaguis: I wonder if it makes sense to allow exposing grafana and allow having an insecure default password so easily. So if a user does

```
  grafana {
    ingress {
      host                       = "grafana.mydomain.net"
      class                      = "contour"
      certmanager_cluster_issuer = "letsencrypt-production"
    }
  }
```

and this exposes grafana with admin:admin password, this is surprising and insecure. Should we do something about it?
surajssd: > I wonder if it makes sense to allow exposing grafana and allow having an insecure default password so easily.

@iaguis there is a default password but it is not `admin`. The password if not specified is generated by helm automatically and stored in a secret, as mentioned in the docs.
iaguis: > @iaguis there is a default password but it is not `admin`. The password if not specified is generated by helm automatically and stored in a secret, as mentioned in the docs.

Ah, all good then :+1: 
invidian: How about something like this?

```diff
diff --git a/pkg/components/prometheus-operator/component.go b/pkg/components/prometheus-operator/component.go
index b3791da3..137b997f 100644
--- a/pkg/components/prometheus-operator/component.go
+++ b/pkg/components/prometheus-operator/component.go
@@ -123,7 +123,6 @@ func newComponent() *component {
                                "tier":    "control-plane",
                        },
                },
-               Grafana: &Grafana{},
        }
 }

diff --git a/pkg/components/prometheus-operator/component_test.go b/pkg/components/prometheus-operator/component_test.go
index 8e2608fb..b0b6cd39 100644
--- a/pkg/components/prometheus-operator/component_test.go
+++ b/pkg/components/prometheus-operator/component_test.go
@@ -26,18 +26,25 @@ func TestEmptyConfig(t *testing.T) {
        c := newComponent()
        emptyConfig := hcl.EmptyBody()
        evalContext := hcl.EvalContext{}
-       diagnostics := c.LoadConfig(&emptyConfig, &evalContext)

-       if diagnostics.HasErrors() {
+       if d := c.LoadConfig(&emptyConfig, &evalContext); d.HasErrors() {
                t.Fatalf("Empty config should not return errors")
        }
+
+       m, err := c.RenderManifests()
+       if err != nil {
+               t.Fatalf("Rendering manifests with valid config should succeed, got: %s", err)
+       }
+       if len(m) <= 0 {
+               t.Fatalf("Rendered manifests shouldn't be empty")
+       }
 }

 func TestRenderManifest(t *testing.T) {
        configHCL := `
 component "prometheus-operator" {
   grafana {
-       admin_password = "foobar"
+    admin_password = "foobar"
   }
   namespace = "monitoring"
 }
diff --git a/pkg/components/prometheus-operator/template.go b/pkg/components/prometheus-operator/template.go
index 3a96fe0f..7089874c 100644
--- a/pkg/components/prometheus-operator/template.go
+++ b/pkg/components/prometheus-operator/template.go
@@ -48,7 +48,6 @@ alertmanager:
               storage: "{{.AlertManagerStorageSize}}"

 grafana:
-  adminPassword: {{.Grafana.AdminPassword}}
   plugins: "grafana-piechart-panel"
   testFramework:
     enabled: false
@@ -57,6 +56,8 @@ grafana:
       searchNamespace: ALL
   rbac:
     pspUseAppArmor: false
+  {{- if .Grafana}}
+  adminPassword: {{.Grafana.AdminPassword}}
   {{ if .Grafana.Ingress }}
   ingress:
     enabled: true
@@ -71,6 +72,7 @@ grafana:
       - {{ .Grafana.Ingress.Host }}
       secretName: {{ .Grafana.Ingress.Host }}-tls
   {{ end }}
+  {{- end}}

 kubeEtcd:
   enabled: {{.Monitor.Etcd}}
```
surajssd: @invidian PTAL, added table driven tests. Also taken care of the test that fails.

Patch:
diff --git a/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/kubecontrollersconfigurations.yaml b/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/kubecontrollersconfigurations.yaml
deleted file mode 100644
index 44b0c9a3..00000000
--- a/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/kubecontrollersconfigurations.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: kubecontrollersconfigurations.crd.projectcalico.org
-spec:
-  scope: Cluster
-  group: crd.projectcalico.org
-  version: v1
-  names:
-    kind: KubeControllersConfiguration
-    plural: kubecontrollersconfigurations
-    singular: kubecontrollersconfiguration
diff --git a/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/templates/deployment.yaml b/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/templates/deployment.yaml
index c77e9cd8..9181af82 100644
--- a/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/templates/deployment.yaml
+++ b/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/templates/deployment.yaml
@@ -42,10 +42,6 @@ spec:
               value: node
             - name: DATASTORE_TYPE
               value: kubernetes
-            # This is disabled until the HostEndpoints created by this controller are better
-            # parameterised. See https://github.com/projectcalico/calico/issues/3566.
-            # - name: AUTO_HOST_ENDPOINTS
-            #   value: "enabled"
           readinessProbe:
             exec:
               command:
@@ -97,16 +93,6 @@ rules:
       - create
       - update
       - delete
-  # kube-controllers manages hostendpoints.
-  - apiGroups: ["crd.projectcalico.org"]
-    resources:
-      - hostendpoints
-    verbs:
-      - get
-      - list
-      - create
-      - update
-      - delete
   # Needs access to update clusterinformations.
   - apiGroups: ["crd.projectcalico.org"]
     resources:
@@ -123,19 +109,6 @@ rules:
       - use
     resourceNames:
       - calico-kube-controllers
-  # KubeControllersConfiguration is where it gets its config
-  - apiGroups: ["crd.projectcalico.org"]
-    resources:
-      - kubecontrollersconfigurations
-    verbs:
-      # read its own config
-      - get
-      # create a default if none exists
-      - create
-      # update status
-      - update
-      # watch for changes
-      - watch
 ---
 kind: ClusterRoleBinding
 apiVersion: rbac.authorization.k8s.io/v1
diff --git a/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/values.yaml b/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/values.yaml
index bd934ff4..d368bae9 100644
--- a/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/values.yaml
+++ b/assets/lokomotive-kubernetes/bootkube/resources/charts/calico/values.yaml
@@ -1,8 +1,8 @@
 calico:
   networkMTU: 1500
-  image: calico/node:v3.14.1
-  cniImage: calico/cni:v3.14.1
-  controllersImage: calico/kube-controllers:v3.14.1
+  image: calico/node:v3.13.3
+  cniImage: calico/cni:v3.13.3
+  controllersImage: calico/kube-controllers:v3.13.3
   enableReporting: false
   networkIpAutodetectionMethod: first-found
   ipipEnabled: true
diff --git a/assets/lokomotive-kubernetes/bootkube/variables.tf b/assets/lokomotive-kubernetes/bootkube/variables.tf
index 98462c55..290efb8a 100644
--- a/assets/lokomotive-kubernetes/bootkube/variables.tf
+++ b/assets/lokomotive-kubernetes/bootkube/variables.tf
@@ -89,9 +89,9 @@ variable "container_images" {
   type        = map(string)
 
   default = {
-    calico                  = "calico/node:v3.14.1"
-    calico_cni              = "calico/cni:v3.14.1"
-    calico_controllers      = "calico/kube-controllers:v3.14.1"
+    calico                  = "calico/node:v3.13.3"
+    calico_cni              = "calico/cni:v3.13.3"
+    calico_controllers      = "calico/kube-controllers:v3.13.3"
     hyperkube               = "k8s.gcr.io/hyperkube:v1.18.3"
     coredns                 = "coredns/coredns:coredns-"
     pod_checkpointer        = "kinvolk/pod-checkpointer:83e25e5968391b9eb342042c435d1b3eeddb2be1"
diff --git a/ci/aks/aks-cluster.lokocfg.envsubst b/ci/aks/aks-cluster.lokocfg.envsubst
index cf0fad65..2f95d400 100644
--- a/ci/aks/aks-cluster.lokocfg.envsubst
+++ b/ci/aks/aks-cluster.lokocfg.envsubst
@@ -25,10 +25,6 @@ variable "resource_group_name" {
   default = "$CLUSTER_ID"
 }
 
-variable "grafana_admin_password" {
-  default = "admin"
-}
-
 variable "asset_dir" {
   default = "~/lokoctl-assets"
 }
@@ -71,8 +67,7 @@ cluster "aks" {
 }
 
 component "prometheus-operator" {
-  grafana_admin_password = var.grafana_admin_password
-  disable_webhooks       = true
+  disable_webhooks = true
 
   monitor {
     etcd                    = false
diff --git a/ci/aws/aws-cluster.lokocfg.envsubst b/ci/aws/aws-cluster.lokocfg.envsubst
index 341e0f0f..28003f5b 100644
--- a/ci/aws/aws-cluster.lokocfg.envsubst
+++ b/ci/aws/aws-cluster.lokocfg.envsubst
@@ -47,9 +47,7 @@ component "openebs-storage-class" {
   }
 }
 
-component "prometheus-operator" {
-  grafana_admin_password = "admin"
-}
+component "prometheus-operator" {}
 
 component "contour" {
   ingress_hosts     = ["dex.$CLUSTER_ID.$AWS_DNS_ZONE", "gangway.$CLUSTER_ID.$AWS_DNS_ZONE"]
diff --git a/ci/packet/packet-cluster.lokocfg.envsubst b/ci/packet/packet-cluster.lokocfg.envsubst
index 1943c49d..2795ba91 100644
--- a/ci/packet/packet-cluster.lokocfg.envsubst
+++ b/ci/packet/packet-cluster.lokocfg.envsubst
@@ -47,9 +47,7 @@ component "openebs-storage-class" {
   }
 }
 
-component "prometheus-operator" {
-  grafana_admin_password = "admin"
-}
+component "prometheus-operator" {}
 
 component "contour" {
   ingress_hosts     = ["dex.$CLUSTER_ID.$AWS_DNS_ZONE","gangway.$CLUSTER_ID.$AWS_DNS_ZONE"]
diff --git a/docs/configuration-reference/components/prometheus-operator.md b/docs/configuration-reference/components/prometheus-operator.md
index 50708626..559a24d8 100644
--- a/docs/configuration-reference/components/prometheus-operator.md
+++ b/docs/configuration-reference/components/prometheus-operator.md
@@ -29,8 +29,16 @@ Prometheus Operator component configuration example:
 
 ```tf
 component "prometheus-operator" {
-  namespace              = "monitoring"
-  grafana_admin_password = "foobar"
+  namespace = "monitoring"
+
+  grafana {
+    admin_password = "foobar"
+    ingress {
+      host                       = "grafana.mydomain.net"
+      class                      = "contour"
+      certmanager_cluster_issuer = "letsencrypt-production"
+    }
+  }
 
   etcd_endpoints = [
     "10.88.181.1",
@@ -85,8 +93,11 @@ Example:
 
 | Argument | Description | Default | Required |
 |--------	|--------------|:-------:|:--------:|
-| `namespace` | Namespace to deploy the Prometheus Operator. | - | true |
-| `grafana_admin_password` | Password for `admin` user in Grafana.  | - | true |
+| `namespace` | Namespace to deploy the Prometheus Operator. | `monitoring` | false |
+| `grafana.admin_password` | Password for `admin` user in Grafana. If not provided it is auto generated and stored in secret `prometheus-operator-grafana`.  | - | false |
+| `grafana.ingress.host` | Ingress URL host to expose Grafana over the internet. **NOTE:** When running on Packet, a DNS entry pointing at the ingress controller needs to be created.  | - | true |
+| `grafana.ingress.class` | Ingress class to use for Grafana ingress. | `contour` | false |
+| `grafana.ingress.certmanager_cluster_issuer` | `ClusterIssuer` to be used by cert-manager while issuing TLS certificates. Supported values: `letsencrypt-production`, `letsencrypt-staging`.  | `letsencrypt-production` | false |
 | `etcd_endpoints` | List of endpoints where etcd can be reachable from Kubernetes. | [] | false |
 | `prometheus_operator_node_selector` | Node selector to specify nodes where the Prometheus Operator pods should be deployed. | {} | false |
 | `prometheus_metrics_retention` | Time duration Prometheus shall retain data for. Must match the regular expression `[0-9]+(ms\|s\|m\|h\|d\|w\|y)` (milliseconds, seconds, minutes, hours, days, weeks and years). | `10d` | false |
diff --git a/examples/aks-production/cluster.lokocfg b/examples/aks-production/cluster.lokocfg
index 3aa711d7..5c1cff56 100644
--- a/examples/aks-production/cluster.lokocfg
+++ b/examples/aks-production/cluster.lokocfg
@@ -1,6 +1,5 @@
 variable "subscription_id" {}
 variable "tenant_id" {}
-variable "grafana_admin_password" {}
 variable "resource_group_name" {}
 variable "cert_manager_email" {}
 variable "state_s3_bucket" {}
@@ -67,7 +66,6 @@ cluster "aks" {
 }
 
 component "prometheus-operator" {
-  grafana_admin_password = var.grafana_admin_password
   disable_webhooks       = true
 
   monitor {
diff --git a/examples/aws-production/cluster.lokocfg b/examples/aws-production/cluster.lokocfg
index 169e084c..745ed8b9 100644
--- a/examples/aws-production/cluster.lokocfg
+++ b/examples/aws-production/cluster.lokocfg
@@ -1,7 +1,6 @@
 variable "dns_zone" {}
 variable "route53_zone_id" {}
 variable "ssh_public_keys" {}
-variable "grafana_admin_password" {}
 variable "state_s3_bucket" {}
 variable "lock_dynamodb_table" {}
 variable "oidc_issuer_url" {}
@@ -74,6 +73,4 @@ component "openebs-operator" {}
 
 component "openebs-storage-class" {}
 
-component "prometheus-operator" {
-  grafana_admin_password = var.grafana_admin_password
-}
+component "prometheus-operator" {}
diff --git a/examples/packet-production/cluster.lokocfg b/examples/packet-production/cluster.lokocfg
index ad1d576b..bc772132 100644
--- a/examples/packet-production/cluster.lokocfg
+++ b/examples/packet-production/cluster.lokocfg
@@ -5,7 +5,6 @@ variable "ssh_public_keys" {}
 variable "management_cidrs" {}
 variable "node_private_cidr" {}
 variable "cert_manager_email" {}
-variable "grafana_admin_password" {}
 variable "state_s3_bucket" {}
 variable "lock_dynamodb_table" {}
 variable "metallb_address_pool" {}
@@ -107,8 +106,6 @@ component "cert-manager" {
 
 component "openebs-storage-class" {}
 
-component "prometheus-operator" {
-  grafana_admin_password = var.grafana_admin_password
-}
+component "prometheus-operator" {}
 
 component "flatcar-linux-update-operator" {}
diff --git a/pkg/assets/generated_assets.go b/pkg/assets/generated_assets.go
index a9eec7ba..f9f03ee4 100644
--- a/pkg/assets/generated_assets.go
+++ b/pkg/assets/generated_assets.go
@@ -3832,13 +3832,6 @@ var vfsgenAssets = func() http.FileSystem {
 
 			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\x8e\xb1\x4e\xc5\x30\x0c\x45\xf7\x7c\x85\xbf\x20\xa8\x1b\xca\xfa\x58\xd8\x9e\x18\xd8\x4d\x6a\x2a\xd3\x34\xb6\x6c\xa7\xe2\xf3\x51\x0b\x65\x7a\xa3\x8f\x7c\xef\x3d\xa8\xfc\x4e\xe6\x2c\xbd\x00\x2a\xd3\x77\x50\x3f\x2e\xcf\xeb\xb3\x67\x96\xa7\x7d\xfa\xa0\xc0\x29\xad\xdc\xe7\x02\xb7\xe1\x21\xdb\x1b\xb9\x0c\xab\xf4\x42\x9f\xdc\x39\x58\x7a\xda\x28\x70\xc6\xc0\x92\x00\x3a\x6e\x54\x80\x55\x45\x9a\xe7\x6a\x73\x56\x93\x2f\xaa\x51\xb1\x71\x95\x2c\xb6\x24\x57\xaa\xc7\xaf\x57\x51\x2a\x70\x6b\xc3\x83\x2c\x01\x2c\x26\x43\x0b\x3c\x4e\x01\xec\x97\xec\x3e\xfd\x2d\xf9\x51\x03\xf0\xeb\xf7\x7a\xbf\x8b\xb4\x13\x68\x1b\x86\xed\xdf\xe3\x64\xce\x7d\x19\x0d\xed\xa2\xe9\x27\x00\x00\xff\xff\x2c\x31\xd0\xa6\xff\x00\x00\x00"),
 		},
-		"/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/kubecontrollersconfigurations.yaml": &vfsgen۰CompressedFileInfo{
-			name:             "kubecontrollersconfigurations.yaml",
-			modTime:          time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC),
-			uncompressedSize: 343,
-
-			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\x3d\x4e\xc6\x30\x0c\x40\xf7\x9c\xc2\x27\x28\xea\x86\xb2\x96\x8d\x8d\x81\xdd\x4d\xfd\x55\xa6\x69\x1c\xf9\xa7\xe2\xf8\xa8\x05\x04\x03\xe2\x1b\x2d\x3d\x3f\x3f\x63\xe7\x57\x52\x63\x69\x19\xb0\x33\xbd\x3b\xb5\x73\xb2\x61\x7b\xb4\x81\xe5\xe1\x18\x67\x72\x1c\xd3\xc6\x6d\xc9\x30\x85\xb9\xec\x2f\x64\x12\x5a\xe8\x89\x6e\xdc\xd8\x59\x5a\xda\xc9\x71\x41\xc7\x9c\x00\x1a\xee\x94\x61\x8b\x99\x8a\x34\x57\xa9\x95\xd4\x8a\xb4\x1b\xaf\xa1\xe8\x97\xbd\xe8\x32\x74\x95\x37\x2a\x5e\xb0\x72\x91\x41\x74\x4d\xd6\xa9\x9c\x06\x2b\xd2\x29\xc3\x54\xc3\x9c\x34\x01\xac\x2a\xd1\x33\xfc\xbd\x05\x70\x7c\xbf\x70\x8c\x5f\xf7\xed\xd4\x00\x7c\x56\x3f\xc7\x4c\xd3\x4f\xca\xf4\x3b\xe5\xc2\x7a\x0d\xc5\x7a\xa7\xf9\x22\x8d\xdb\x1a\x15\xf5\x7f\x36\x7d\x04\x00\x00\xff\xff\x6d\x5a\x93\x3e\x57\x01\x00\x00"),
-		},
 		"/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/networkpolicies.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "networkpolicies.yaml",
 			modTime:          time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC),
@@ -3888,9 +3881,9 @@ var vfsgenAssets = func() http.FileSystem {
 		"/lokomotive-kubernetes/bootkube/resources/charts/calico/templates/deployment.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "deployment.yaml",
 			modTime:          time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC),
-			uncompressedSize: 3783,
+			uncompressedSize: 2988,
 
-			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x56\x5d\x6f\xdb\x36\x17\xbe\xf7\xaf\x38\x88\x2f\x7a\x25\xf9\xed\x3b\xac\x28\x74\xe7\x26\xc6\x5a\x2c\x75\x82\xd8\x2b\x30\x0c\x43\x40\x93\xc7\x16\x67\x8a\x87\xe5\xa1\x9c\x78\x45\xff\xfb\x40\x4a\x76\x24\x47\x69\xd3\x75\xd5\x1d\xc5\xf3\xf1\x9c\xe7\x7c\x71\x0c\xb3\xfb\xe0\x85\x0c\xa8\x60\xed\xa9\x82\x32\x04\xc7\xc5\x64\xa2\x48\x72\xee\x3c\xfd\x85\x32\x48\x61\xb4\xa4\x9c\xfc\x66\x52\x09\xab\xd7\xc8\x81\x27\xed\xcf\xbd\xa8\xcc\x48\x38\xfd\x01\x3d\x6b\xb2\x05\x08\xe7\x78\xb2\x7b\x39\xda\x6a\xab\x0a\xb8\x40\x67\x68\x5f\xa1\x0d\xa3\x0a\x83\x50\x22\x88\x62\x04\x60\x45\x85\x05\x34\x26\xb2\x6d\xbd\xc2\x4c\x92\x0d\x9e\x8c\x41\xcf\xed\x3d\x3b\x21\xb1\x80\x74\xcb\x7b\x0e\x58\x8d\x00\x8c\x58\xa1\xe1\x68\x02\x60\xfb\x9a\x33\xe1\xdc\xd3\x76\xd8\xa1\x8c\xa2\x63\x58\x96\x08\x9d\x1b\x90\xc2\x02\x59\xb3\x87\x52\xec\x10\x04\xb0\xb6\x1b\x83\x20\x64\xd0\x3b\x04\x6d\x39\x08\x2b\x31\x1f\x01\x78\x74\x46\x4b\xc1\x05\xbc\x1c\x01\x30\x1a\x94\x81\x7c\x03\xa0\x12\x41\x96\x97\x1d\x44\xcf\xc0\x04\xc0\xc1\x8b\x80\x9b\x7d\xa3\x12\xf6\x0e\x0b\xb8\x41\xe9\x51\x04\x1c\x01\x04\xac\x9c\x11\x01\x5b\x17\x1d\xd2\xe2\xf7\x35\xe2\x0e\x32\x83\xe4\xc5\xcf\xf4\xe0\x3e\x0b\x70\xfc\x84\xb5\x14\x44\xd0\x64\x3b\xba\x2c\x4b\x54\xb5\x41\x9f\x0b\xe3\x4a\x91\x47\x5d\x6f\x31\x20\xe7\x9a\x26\xd2\xeb\xa0\xa5\x30\x99\x23\x55\xc0\x8b\x17\x49\xed\x90\x92\x84\x93\x14\x2e\x7a\x84\x26\x40\x3d\x23\xc4\x05\x18\x6d\xeb\xfb\xf6\x3e\x90\x41\x7f\x8a\x63\x0c\xef\x85\xdf\x42\x28\x11\x1c\x29\x10\x0c\x02\x0e\xde\x41\x28\x95\x91\x85\x35\x79\xf0\xd8\x22\xd6\x76\x93\x1f\xb5\x33\xd8\xe2\xbe\x80\xf3\x56\x61\xaa\x14\x59\xbe\xb2\x66\x7f\x94\x00\x20\x17\xbd\x92\x2f\x60\x76\xaf\x39\xf0\xa9\x72\x0c\x25\xf3\x64\xf0\x84\x83\x4a\x70\x40\xdf\x31\x84\xeb\x35\xca\x50\xc0\x9c\x16\x2d\x79\xed\x25\xa3\xdf\x69\x89\x53\x29\xa9\xb6\x61\xfe\x8c\x34\x3b\xaf\xc9\xeb\xb0\x3f\x37\x82\xb9\x51\x68\x32\x9d\x49\x53\x47\xb7\xd9\x81\x83\x56\x21\x9a\x10\xda\xa2\xef\x50\x97\x3d\xab\xa2\xe2\xa7\x2b\xb1\xc1\x02\xe0\xd3\x27\xc8\x3f\x08\x53\x23\xe7\xed\x08\xe8\xc8\xbf\x8b\x42\xf0\xf9\x73\x37\x62\xbb\x2b\x3a\xc7\x98\xad\xf3\x92\x88\x11\xee\x4a\x2d\xcb\x5e\x5b\x06\x02\x5f\xdb\xbc\x27\x7e\x40\x38\x9b\x4f\xdf\x5c\xce\x2e\x6e\xcf\xaf\xe6\xcb\x9b\xab\xcb\xcb\xd9\xcd\xa2\x27\x07\xb0\x8b\xa8\x9a\x5c\x0c\x5a\xb8\x98\x2e\xa7\x8b\xe5\xd5\xcd\xec\x76\xf9\xfb\xf5\x6c\x58\xf9\x21\x7d\x27\x98\x97\xa5\x66\xd0\x0c\x4a\xb3\x58\x19\x54\x50\xdb\xa0\x4d\xaa\xb9\xb7\xc4\x61\x66\x95\x23\x6d\x03\x43\xd3\xc8\x0a\x56\x7b\x08\x51\xe7\x21\x3e\x10\x1e\x61\x85\xa1\x5f\x11\xd1\xb8\x13\x5e\x54\x18\xd0\x6b\x46\x95\xc3\x02\xf1\x38\x87\x37\x3a\x94\xf5\x2a\x97\x54\x4d\x7a\xd3\xb8\x9d\xbf\x13\xcd\x5c\x23\x4f\x7e\xfa\xf9\xd5\xab\xfc\xc4\xea\x21\xee\xe9\x6f\xcb\xab\xdb\xb7\x57\x8b\xe5\xed\x6c\x7e\x71\x7d\xf5\x6e\xbe\x5c\x9c\x48\x1e\xc3\x3f\x43\x9b\xa2\x3b\xeb\x08\x78\x14\x4a\x5b\x64\xbe\xf6\xb4\xc2\x7e\x2e\xf1\xfe\xa1\x9d\x0f\x9f\xa4\xaa\x12\x56\x9d\xfe\xce\x60\x52\xb3\x9f\xac\xb4\x9d\xc8\x12\xe5\x36\xe3\x20\x42\xcd\x8f\xa4\x32\xdf\xf3\xcd\x54\x7b\x89\xdc\xb7\xe6\xf1\x63\x1d\x97\xd0\xa9\x8f\x0a\x2b\xf2\xfb\x02\xfe\xff\xbf\xf7\x7a\x94\x65\x59\x6f\x31\x1d\x77\xd2\xa2\xd7\x6a\xff\xc5\x5e\x8a\xae\x1a\xdb\xe7\x4d\xeb\xdd\x90\xc1\x9e\x73\xbf\x12\x32\x17\x75\x28\xc9\xeb\xbf\xd3\xfc\xca\xb7\xaf\xd3\x88\xd8\xbd\xfc\x06\x04\xbe\x36\x0d\x17\x63\x98\x93\x42\x4e\x25\x75\x17\xd7\x10\xaa\xd8\x3d\x15\x59\x1d\xc8\xa7\x69\xa7\xd0\x60\x1a\x94\xb1\x2e\x32\x10\x4e\xff\xe2\xa9\x76\x5c\xc0\x1f\x67\x67\x7f\x8e\x06\xe9\xcd\x52\xf7\x34\x49\xd9\xa1\x5f\x75\x2e\x92\x97\xe3\xc9\x68\x0e\xc7\xc3\x06\x43\x82\x74\x4d\xaa\x41\xf4\xb1\x46\xaf\x1b\x44\x29\xd7\x09\x0f\xc6\xc9\x89\xed\x5a\x7d\x36\x1e\x47\x6a\x10\xce\xc1\xe7\xbb\xeb\xe9\xfb\x07\xbd\xe4\x3d\xbe\x51\x5c\x6d\x52\x17\xde\x95\x68\x9b\x98\xd2\x55\xe2\x04\xd5\x00\x02\xe9\xd5\xe3\xe7\xce\xd3\xb0\xb4\x73\x44\x66\x10\x59\x4b\xcd\xf7\xd9\x5f\x19\x92\x5b\xb1\x5e\x6b\xab\x83\x3e\x0e\xa3\xe8\x57\x54\xe9\xae\xff\xab\x14\x56\x99\xe1\xbc\x35\x44\x0d\x64\xed\xf8\xe2\x68\x8e\xb5\x53\xdd\x63\xc3\x54\xa2\xf8\xb4\x0a\x23\xc1\x62\x83\x0c\x25\xc5\x84\xb6\x83\xef\xfb\x39\xed\x99\xfb\x31\xa1\xcc\x11\x63\x89\x4a\x89\x9c\xb6\x4d\x23\x09\xed\xc2\xd4\x76\x4d\xbe\x12\x4f\x35\xcd\x37\x86\x33\x60\xf4\x6b\x41\x3d\x15\xc7\x18\xa6\xc6\xd0\x1d\xd4\xf1\x9d\x0a\xd7\x8b\xeb\xc7\xe0\x1c\x19\x2d\xf7\x5f\xee\x23\x94\x75\x7c\x30\x24\x51\x3d\x5c\x2d\x35\x63\xcf\x42\x7c\x57\x74\x63\x7a\x72\x32\x8e\xe1\xd7\x7a\x85\xe7\x0f\xff\xce\xc9\xae\xf5\xa6\x6e\x1e\x6b\x71\x73\xde\x95\xe8\x11\x74\x88\x11\x33\xe8\x90\x56\xe3\x5a\x6f\xbe\x9b\xe8\x88\xa6\x03\x46\x76\x1d\x0f\x04\x39\x4e\x1b\x2d\x01\xa0\x3b\xfb\x00\xe2\x34\x1d\xe3\x36\x1d\x20\x40\xe1\x5a\xd4\x26\x80\x5e\x83\x25\x8b\xcd\x28\xe3\xe1\xb4\x8d\x0f\x45\xd5\xdb\x6f\x27\x45\x39\x6e\xc6\x69\x9a\x8b\xb2\x14\x76\xd3\x69\xf1\x66\xd0\x0e\xae\x94\x37\xda\x2a\x6d\x37\x3f\x64\xb3\x90\xc1\x1b\x5c\x47\xc1\x43\x2e\xbe\x60\x7b\x04\xf0\x78\xdf\x7d\xcd\x05\xd7\xab\x98\x52\x2e\x46\x19\x0c\x6e\xe2\x7f\xbd\x7f\x47\xff\x04\x00\x00\xff\xff\xd2\xfa\x1e\xb0\xc7\x0e\x00\x00"),
+			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x56\x4d\x6f\xdb\x38\x13\xbe\xeb\x57\x0c\x9a\x43\x4f\x92\xdf\xbe\xa7\x42\x37\x37\x35\x16\x05\xd2\xc4\xb0\x83\x02\x8b\xc5\xa2\x18\x93\x63\x8b\x6b\x8a\xc3\x72\x28\x27\xde\xa2\xff\x7d\x41\x49\x76\xa5\x44\x69\xd2\xfd\xe0\x8d\x9a\xaf\x87\xcf\x0c\x1f\xea\x02\x16\xf7\x31\xa0\x8a\xa4\x61\x1b\xb8\x86\x2a\x46\x2f\xe5\x6c\xa6\x59\x49\xe1\x03\xff\x41\x2a\x2a\xb4\x46\x71\xc1\x61\x37\xab\xd1\x99\x2d\x49\x94\x59\xff\xf1\x88\xb5\xcd\xd0\x9b\x4f\x14\xc4\xb0\x2b\x01\xbd\x97\xd9\xe1\x4d\xb6\x37\x4e\x97\xf0\x9e\xbc\xe5\x63\x4d\x2e\x66\x35\x45\xd4\x18\xb1\xcc\x00\x1c\xd6\x54\x42\x97\x22\xdf\x37\x1b\xca\x15\xbb\x18\xd8\x5a\x0a\xd2\xdb\xc5\xa3\xa2\x12\x5a\xab\x1c\x25\x52\x9d\x01\x58\xdc\x90\x95\x94\x02\x60\xff\x56\x72\xf4\xfe\xe9\x3c\xe2\x49\x25\xd7\x0b\xb8\xad\x08\x06\x16\x50\xe8\x80\x9d\x3d\x42\x85\x07\x02\x04\x31\x6e\x67\x09\x50\x45\x73\x20\x30\x4e\x22\x3a\x45\x45\x06\x10\xc8\x5b\xa3\x50\x4a\x78\x93\x01\x08\x59\x52\x91\x43\x07\xa0\xc6\xa8\xaa\xab\x01\xa2\x17\x60\x02\x90\x18\x30\xd2\xee\xd8\x85\xc4\xa3\xa7\x12\x56\xa4\x02\x61\xa4\x0c\x20\x52\xed\x2d\x46\xea\x4b\x0c\x48\x4b\xeb\x39\xe2\x4e\x3e\x93\xe4\xa5\x65\x47\x70\x5f\x04\x38\x2d\x74\x8e\x23\x46\xc3\x6e\x10\x2b\xaa\x22\xdd\x58\x0a\x05\x5a\x5f\x61\x91\x62\x83\xa3\x48\x52\x18\x9e\xa9\x60\xa2\x51\x68\x73\xcf\xba\x84\xd7\xaf\xdb\xb0\x53\x4b\x5a\x9c\xac\x69\x3d\x22\xb4\x05\x34\x4a\xc2\x52\x82\x35\xae\xb9\xef\xed\x91\x2d\x85\x87\x38\x2e\xe0\x23\x86\x3d\xc4\x8a\xc0\xb3\x06\x14\x40\x38\x55\x07\xd4\x3a\x67\x07\x5b\x0e\x10\xa8\x47\x6c\xdc\xae\x38\x47\xe7\xb0\xa7\x63\x09\x97\x7d\xc0\x5c\x6b\x76\x72\xe3\xec\xf1\xec\x01\xc0\x3e\x55\xe5\x50\xc2\xe2\xde\x48\x94\x87\xc1\xe9\x28\x79\x60\x4b\x0f\x38\xa8\x51\x22\x85\x41\x22\xda\x6e\x49\xc5\x12\xae\x79\xdd\x93\xd7\x1b\x85\xc2\xc1\x28\x9a\x2b\xc5\x8d\x8b\xd7\x2f\x68\xb3\x0f\x86\x83\x89\xc7\x4b\x8b\x22\x5d\x40\xd7\xe9\x5c\xd9\x26\x95\xcd\x4f\x1c\xf4\x01\x29\x05\x1a\x47\x61\x40\x5d\xfe\xa2\x89\x4a\xcb\xd4\xb8\xa3\x12\xe0\xeb\x57\x28\x3e\xa1\x6d\x48\x8a\x5e\x02\x06\xfe\x1f\x92\x13\x7c\xfb\x36\x3c\xb1\x3b\x94\x83\x6d\xea\xd6\x65\xc5\x2c\x04\x77\x95\x51\xd5\xe8\x5a\x46\x86\xd0\xb8\x62\xe4\x7e\x42\xb8\xb8\x9e\xbf\xbb\x5a\xbc\xff\x7c\x79\x73\x7d\xbb\xba\xb9\xba\x5a\xac\xd6\x23\x3f\x80\x43\x42\xd5\xf5\x62\x32\xc3\xfb\xf9\xed\x7c\x7d\x7b\xb3\x5a\x7c\xbe\xfd\x75\xb9\x98\x0e\xfe\xde\xbe\x81\x3d\x10\x6a\xe3\x48\x64\x19\x78\x43\xe3\xd3\xd0\xfd\xf7\x81\x3e\x2d\xc5\x75\x8d\x4e\x3f\xfc\x9c\xc3\xac\x91\x30\xdb\x18\x37\x53\x15\xa9\x7d\x2e\x11\x63\x23\x8f\xbc\xf2\x30\xaa\x2d\xdc\x04\x45\x32\xce\x16\xe8\x4b\x93\x64\xf8\x61\x8d\x9a\x6a\x0e\xc7\x12\xfe\xff\xbf\x8f\x26\xcb\xf3\x7c\x24\xcd\x67\x55\x5e\x8f\x86\xed\xdf\x50\xe6\x54\xaa\xcb\x7d\xd9\x0d\xdf\x8a\x2d\x8d\x8a\x87\x0d\xaa\x02\x9b\x58\x71\x30\x7f\xb6\x37\xb8\xd8\xbf\x6d\x2f\xc9\xe1\xcd\x4f\x20\x08\x8d\xed\xb8\xb8\x80\x6b\xd6\x24\x80\x81\xe0\x2e\x09\x31\xe9\x34\x3f\x35\x3b\x13\x39\xb4\xf7\x5d\x93\xa5\x56\x2a\xd2\x44\xe5\x80\xde\xfc\x12\xb8\xf1\x52\xc2\x6f\xaf\x5e\xfd\x9e\x4d\xd2\x9b\xb7\xf3\xd3\x35\xe5\x40\x61\x33\x30\xb4\x55\xce\x3b\x6b\x24\x9e\x37\x3b\x8a\x2d\xa4\x25\xeb\x0e\xd1\x97\x86\x82\xe9\x10\xb5\xbd\x6e\xf1\x50\xd2\x0e\xea\x1f\x96\x17\xe3\xf1\xac\x27\xe1\x9c\x6a\x7e\x58\xce\x3f\x7e\x8f\x6b\xab\xa7\x57\xda\x37\xe9\x15\xd1\x70\x57\x91\xeb\xce\xd4\x9a\x5a\x4e\x48\x4f\x20\x50\x41\x3f\x7e\xf0\x9f\x86\x65\xbc\x67\xb6\x93\xc8\x7a\x6a\xfe\x59\xfe\x8d\x65\xb5\xc7\xed\xd6\x38\x13\xcd\xf9\x3a\xa6\xba\x58\xb7\xb6\xf1\xa7\x0a\x9d\xb6\xd3\x7d\xeb\x88\x9a\xe8\xda\xf9\xcd\xed\xb6\x8d\xd7\xc3\x6d\xc7\x54\x37\x69\x44\xa9\xaf\x4a\x91\xb4\x22\xd5\x79\x42\xaf\xb3\xc6\x6d\x39\xd4\xf8\xd4\xa4\xfd\xe4\xb9\x27\x92\x3e\x77\xa8\xa7\xce\x71\x01\x73\x6b\xf9\x0e\x9a\xf4\x7b\x03\xcb\xf5\xf2\x31\x38\xcf\xd6\xa8\xe3\x8f\x87\x8f\x54\x93\xde\x99\xd6\xd5\x4c\x53\xdc\x08\x8d\x32\xa4\xe7\x68\x78\xa6\x27\x2e\xf3\xa4\x6a\xbc\x33\x4e\x1b\xb7\xfb\x4f\xc4\x83\x2d\xad\x68\x9b\x1c\x4f\x2c\xfc\x20\x77\x06\xf0\x58\xd2\x9e\x2b\x21\xcd\x26\x75\x5a\xca\x2c\x87\x49\xb1\xfd\xdb\x12\x9b\xfd\x15\x00\x00\xff\xff\xd3\xb9\x03\x03\xac\x0b\x00\x00"),
 		},
 		"/lokomotive-kubernetes/bootkube/resources/charts/calico/templates/ippools-default-ipv4.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "ippools-default-ipv4.yaml",
@@ -3909,7 +3902,7 @@ var vfsgenAssets = func() http.FileSystem {
 			modTime:          time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC),
 			uncompressedSize: 350,
 
-			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x90\xcd\x4e\xeb\x30\x10\x85\xf7\x79\x8a\x51\xf6\x4e\x93\x7b\x81\x85\x77\x15\x74\x91\x45\x36\x11\x3c\x80\x63\x4f\xca\xa8\x66\xc6\xf2\x4f\x4b\xdf\x1e\x19\x04\x4d\xb7\x73\xce\xf9\xf4\x69\xac\xf1\x64\x45\x37\x00\x8c\xf9\x22\xf1\x34\xbd\xbe\x69\x18\x1e\xfb\xbe\x01\xa0\x0f\x73\x44\x0d\x3f\x9d\x1d\x8b\x43\x7d\xfe\xdf\x0d\x0f\xdd\xd0\x00\x58\xa6\xf1\x2e\xb7\x4c\xdb\x58\x38\x47\xf1\x1e\x63\xba\xaf\x9d\xca\x82\x6a\x93\x6e\x36\xc8\x66\xf1\x38\x63\x90\x98\x89\x8f\x1a\x56\xe3\x13\xde\xdc\xc6\xb0\x2f\x59\x1c\x66\xb4\x99\x84\x27\xcc\xef\xe2\x34\xac\x14\x53\x56\xab\x14\x76\x55\x3a\x50\x38\x7c\x83\x9c\x86\x1c\x4b\xdd\x9f\x3f\xbd\xe1\xbf\xe3\x2f\xb5\x36\x67\x34\x8e\x18\x53\xd2\xd0\x2a\x50\x6a\xa1\xe8\x54\x44\xe3\xae\x6d\x03\x10\xc4\x3d\x8f\x2f\xb3\x86\xa1\xef\xfe\x75\x7d\xd7\xef\x86\xa7\x9b\xce\x81\xad\x09\xa9\x78\x53\x65\x34\xb4\x95\x37\xd5\x27\xc1\xde\x5f\xcc\x35\xb5\xcd\x57\x00\x00\x00\xff\xff\x4e\x7e\xa6\x52\x5e\x01\x00\x00"),
+			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x90\x31\x6e\xc3\x30\x0c\x45\x77\x9f\x82\xf0\x2e\xc7\xae\xd1\x0e\xda\x82\x36\x83\x07\x2f\x46\x7b\x00\x59\xa2\x53\x22\x2a\x29\x48\x72\xd2\xdc\xbe\x50\x8b\x26\xce\xca\xff\xff\xc3\x03\xad\xf1\x64\x45\x57\x00\x8c\xf9\x22\xf1\x34\xbe\x7f\x68\xe8\x9e\xdb\xb6\x02\xa0\x2f\x73\x44\x0d\x7f\x9d\x1d\x8b\x43\x7d\xee\x9b\xae\x6f\xfa\x0a\xc0\x32\x0d\x0f\xb9\x65\xda\xc6\xc2\x39\x8a\xf7\x18\xd3\x63\xed\xb4\xce\xa8\x36\xe9\x66\x83\x6c\x66\x8f\x13\x06\x89\x99\xf8\xa8\x61\x31\x3e\xe1\xdd\x6d\x08\xfb\x35\x8b\xc3\x8c\x36\x93\xf0\x88\xf9\x53\x9c\x86\x85\x62\xca\x6a\x91\x95\x5d\x91\x0e\x14\x0e\xbf\x20\xa7\x21\xc7\xb5\xec\xcf\xdf\xde\xf0\xed\xf8\x4f\x2d\xcd\x09\x8d\x23\xc6\x94\x34\xd4\x0a\x94\x9a\x29\x3a\x15\xd1\xb8\x6b\x5d\x01\x04\x71\xaf\xc3\xdb\xa4\xa1\x6b\x9b\xa7\xa6\x6d\xda\x5d\xf7\x72\xd7\x39\xb0\x35\x21\xad\xde\x14\x19\x0d\x75\xe1\x8d\xe5\x49\xb0\xf7\x17\x73\x4d\x75\xf5\x13\x00\x00\xff\xff\x22\xca\x51\x5c\x5e\x01\x00\x00"),
 		},
 		"/lokomotive-kubernetes/bootkube/resources/charts/calico.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "calico.yaml",
@@ -4350,7 +4343,7 @@ var vfsgenAssets = func() http.FileSystem {
 			modTime:          time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC),
 			uncompressedSize: 4575,
 
-			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x57\x5d\x6f\xdb\xbc\x15\xbe\xf7\xaf\x38\x48\x0b\xcc\x05\x62\xd9\x8e\x9d\x2c\x0d\xda\x8b\x22\xed\x45\xb0\xb6\xcb\xb6\x6c\xbb\x18\x06\x81\x26\x8f\x24\x22\x14\x49\x1c\x52\x4e\x8c\xa2\xff\xfd\x05\x29\x59\xb6\x1c\x3a\x49\xf1\x36\x37\x82\xc3\xf3\xf1\x1c\x9e\xaf\x87\x6b\x46\x92\xad\x14\xc2\x09\x57\x8d\xf3\x48\xb9\x66\x35\x9e\xc0\x8f\x11\x80\x40\xc7\x49\x5a\x2f\x8d\x86\x8f\x70\x72\xdd\x0a\x40\x14\x18\x01\xf8\x8d\x45\xe8\xfe\x3e\x82\xf3\x24\x75\x39\xfa\x39\x1a\xed\x4c\x32\x2b\x73\x87\xb4\x46\x72\x49\x8b\x5f\xa5\xf3\x60\x0a\x10\xa6\x66\x52\x47\xc3\x0e\x1a\x87\x02\xbc\x01\x42\xc6\x2b\xb8\x6f\x56\x38\x61\x56\xb6\x66\xa0\x20\x53\xc3\x83\xf4\x95\xd4\xe0\x2b\x84\x0e\xf4\x53\x38\x4a\x3a\x3f\x6e\x31\xbd\x0b\xa0\xde\xc0\x7f\x2b\xd4\xa0\x8d\x07\x87\xfe\x34\x2a\xaf\x99\x6a\x30\xf8\x5f\x33\xca\xf6\xb0\xc2\x83\x54\x0a\x56\x18\xa1\x64\xe9\x78\x72\x7c\xf4\x48\x9a\xa9\xdf\x19\x18\xd3\xb0\x35\x0b\x1a\xfd\x83\xa1\xfb\x17\x22\x0b\x9e\x0b\xd6\x28\xdf\x1d\xfe\xef\xff\x47\x33\x90\x4b\xfb\x7c\x16\x98\x10\x32\xfc\x8f\x29\xb8\xb9\x5d\x2f\xc3\x6f\x42\xe7\xd0\x05\xd0\x2b\x04\xa9\xb9\x6a\x04\x0a\xe8\xee\xfe\x20\x82\xbb\xaf\xff\x02\x8e\xe4\x65\x21\x39\xf3\x89\x0a\xf9\x25\xe0\xe8\xb9\xf8\xb3\xb5\x13\x6c\x40\x67\x23\x7b\xb9\x44\xf6\x6e\xcd\x39\xf4\xb9\x90\x94\xf4\x7c\xcb\x7c\x15\x9c\x30\x10\x92\x90\x7b\x43\x1b\x78\xa8\x90\x10\x4a\xd4\x48\xcc\xa3\x80\x68\xc1\x81\xab\x4c\xa3\x44\xb8\x3c\xab\x18\x47\x01\x63\x6e\xb4\x67\x52\x3b\x70\xc8\x09\xbd\x7b\xf7\xba\x4e\xe2\xca\x34\x22\xb7\x64\xd6\x52\x60\x1a\xd6\x5d\x85\xb0\x15\x80\xc2\x10\x44\x9d\x18\xbf\xe4\xe8\x60\x8c\xb5\xf5\x9b\xce\x7a\x14\xd0\xa6\x57\x38\x0e\xe3\x30\x51\x27\x27\x43\x64\x5d\x9d\xe6\xb5\x6f\xd2\x53\xe3\xfb\x0d\x48\xed\x91\x0a\xc6\x11\xbe\xdd\xfd\xfb\xa9\x27\xdd\xd4\x2b\xa4\x27\x9e\xe6\xe7\xb3\x59\xda\x17\x6a\xce\xac\x6b\x14\x0b\x4e\x92\x5e\xbf\xb7\x92\x30\x90\x84\xda\x08\x04\x94\xbe\x42\x02\x69\xa5\x05\x43\xb0\x7e\x54\x4c\xc3\xd8\x68\xb5\x01\x66\xad\x92\x6d\xbd\x73\xa6\x24\x37\xbf\x70\x2d\xc1\xde\x91\xab\x91\x36\x67\x8d\x37\x02\x3d\xf2\x80\x23\xaf\xd1\x57\x46\x24\x81\x7f\x8b\x47\xb1\xbc\x7a\x95\xd8\x6d\x95\x71\x7e\xd0\x97\xbf\x01\x73\x21\xc9\xf9\x49\x61\x1a\x2d\x0e\xa0\x5b\x23\x72\x2e\x45\xba\xd2\xae\x6f\x3e\xff\x13\x6e\x6e\x81\x98\x2e\x31\x42\x75\x4e\x96\x1a\xfe\xd6\xac\x90\x34\x7a\x74\x60\x8d\x70\xaf\xc7\x31\x9f\x65\x67\xd9\x2c\x9b\x4d\xe7\x17\x07\x38\xba\xea\x3d\x8a\xe5\xc3\x87\x2f\x7f\xff\x3c\x7a\x05\xa0\x6d\x1b\x64\xa3\xd0\x27\xf3\x78\x97\xfd\x9c\x27\x8c\x53\x42\xc4\xae\x08\x63\x2d\xef\xc7\x5a\xbb\x29\xe6\x33\x5f\x3d\xab\x30\x11\xda\x65\xa3\x80\x65\xb4\x17\x75\x22\xe2\x36\xda\x45\x8c\xf6\x6c\x79\x72\xd8\xe5\xed\x0a\x6e\x67\x5a\xee\x9a\xa2\x90\x8f\xc9\x14\xfc\xa3\x41\x0a\x59\x0f\xfe\x5b\x69\x17\xd7\x62\x44\xdb\xea\xf5\x60\x99\x76\x0f\x48\x28\x60\xb5\xe9\xb1\xbe\x3e\x37\x1d\xa6\x4c\x19\xce\xd4\x21\xde\x76\x98\x21\xe5\x8c\x78\x95\x04\xfa\x89\x78\x25\x43\x11\x37\xd4\x03\x0b\xa0\xe3\xf2\xde\xaa\x83\xac\x59\x19\x7e\x13\x0a\xed\xa6\xdd\xf7\xaa\xfb\x4e\x60\x8c\x59\x99\x9d\x02\xa3\xfa\x62\xf9\x0b\xe5\xcd\x6a\x71\xf1\xe4\x8a\x7b\xc8\xd1\x67\x7a\xb7\x5c\x0f\x81\xc5\xe6\x6a\x1c\xc2\xb8\x45\x1d\x51\x01\x6a\x1f\x06\x7f\xb8\xe4\x12\x3d\x4c\xde\xbe\xfd\x11\x78\xc4\xf0\x4e\x7e\x86\xfe\x44\x2d\x50\x24\x70\xd7\xcc\xf6\xfb\x67\x50\x22\x01\x12\x74\xed\x0c\x4f\xfe\x42\x52\xe2\xd1\x54\x1b\x81\x57\xeb\x45\x36\x5f\x66\xf3\x93\x3d\x9d\x9c\x6b\x79\x4c\x87\x6b\x99\x56\x31\xda\x93\x51\x2a\xf0\x9f\x03\x95\x58\x34\x7b\xe7\x43\xfd\x6a\x63\x91\x82\xc8\x53\x98\xf7\x97\x2e\x2b\x39\x65\xd2\x4c\x7b\xa9\xab\xf5\x3c\x9b\x5f\x66\x8b\xce\x79\x77\x99\xa9\x18\x8f\x54\x43\xab\x18\x07\x54\x85\xfc\xde\x9a\xb8\x5d\xf6\xbd\x4a\xbd\x36\xea\x7e\x6a\x8d\x98\xec\x8b\x5c\x5d\x2e\xf0\xec\x1c\xcf\xdf\x5f\x5c\x2e\xde\xcf\x57\xef\x71\xb5\x58\x9e\xcd\x96\x67\x7c\xb9\x38\x17\xf3\xd5\x02\x51\x88\xd5\xd9\x0a\xbb\xb8\x86\x73\xe0\x58\x5c\x43\x12\x34\x0c\x2e\x5a\xd8\xdd\x5b\x5e\x33\xcd\x4a\xa4\x94\x85\x9d\xd4\xa4\x93\x4a\x98\x72\xbc\x42\xd1\xa8\x17\xc0\xf4\x52\x09\x0b\x96\xcc\xe3\xe6\xb9\x34\x45\x0b\x51\x6a\x5f\xfb\xe7\x01\x37\xd3\xe1\x9b\x13\x5a\x43\x5e\xea\xb2\xed\xa1\x61\x6d\xaf\x8c\x51\x4f\x1b\xeb\x4b\xd4\x84\xc6\x85\x76\x37\x04\x4c\x33\xb5\xf1\x92\x3b\xe8\x8d\xc5\x5e\xb3\xce\x13\xb2\x1a\xb8\xa9\xad\xd1\xa8\x3d\x98\x07\x1d\x2a\x73\x7c\x27\x4b\x24\x76\x05\xd7\xbb\x5d\x37\xec\xfa\x82\x29\x87\x43\xbc\x9e\xc2\x08\x13\x79\x60\xa7\xee\x45\x5a\x17\x7a\x7c\x47\xec\x8c\xde\xbe\x31\x20\x74\x9b\xeb\x98\x5e\x34\xd9\x53\x5e\x07\x8c\x10\xee\xd1\xfa\xd7\x0f\xa7\x69\xe3\x68\xea\x2a\x46\x38\xe5\x6c\xb2\x47\x9c\xdd\xe1\xc4\x8a\xa8\xd7\x4c\x49\x21\xfd\x26\xb7\x48\xd2\x88\xbc\x32\xcd\x11\x62\xfc\x9f\x4e\x32\x52\x7a\xa5\xda\x49\xbb\x67\x3e\xd0\xf7\x56\xfb\xb5\x44\xec\xf2\xaf\x17\xb3\x64\x05\xb0\xb2\x24\x2c\x8f\xb3\xb0\x2e\xdd\x01\xc1\xde\x2a\xfe\xb4\xd3\x82\xaf\x6c\x83\x04\xe3\xce\x5f\x1c\xb4\x31\x81\xa7\x40\xc8\x4d\x5d\x1f\x1b\x9d\x7d\x79\x25\x53\xff\x06\x1a\x6d\x8a\x42\x72\xc9\xd4\x29\x78\xac\xad\x21\x46\x9b\x53\xa8\xd9\xa6\x5d\xdf\xb5\x09\xdb\x3b\x6c\x4c\xd3\xf8\xf0\x2a\x94\x1c\x07\x01\x76\xcf\xb0\xdd\x00\xc8\x43\x7d\xa6\xa3\xdc\x3e\xd9\x0e\x1e\x44\x41\xa1\x5d\x5d\x70\xb1\x5c\x2e\x42\x6c\x35\xf3\xbc\x6a\xe9\xf0\x11\x85\x44\xac\x47\xb2\x12\x6c\x1e\x64\xe5\xd1\x1a\x87\xb9\xd1\x39\x53\x2a\xef\x49\x77\xba\x4c\x6e\x8a\x50\xc4\x78\x7a\x08\x62\xcb\x1a\x5a\x63\x22\x34\x40\xa8\xa2\xdd\x80\x8a\x7d\xb0\xa3\xf4\x2e\x48\xc4\x50\x03\xa0\x0c\x6e\x8a\x6d\x06\xa5\x4f\x18\x53\xa1\xa5\xda\xb7\xa3\x42\xff\x17\xd7\x5a\xbb\xb9\x4d\xbc\xcf\x9e\xcf\xf1\x2e\x6c\x21\x5d\xac\x46\x87\xaa\xc8\x03\x4d\x46\x91\x77\xf6\x93\x91\x7f\x6e\xe5\x5b\xaa\x84\xaa\x80\x56\x67\x8b\x09\xa4\x76\x9e\x29\xd5\x12\xa6\xce\xfb\x11\x74\x03\x1c\xc3\x85\x91\xe3\xa3\x27\x96\x17\x8a\x95\xe9\x04\x7c\x09\xe7\x10\xcf\xc1\x86\xf7\x62\x64\xfd\x01\xd0\x64\x0f\xd0\x2e\x33\x2f\xbd\x60\x93\x2f\xea\x3f\x02\x00\x00\xff\xff\x29\x69\x8e\xfd\xdf\x11\x00\x00"),
+			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x57\x5d\x6f\xdb\xbc\x15\xbe\xf7\xaf\x38\x48\x0b\xcc\x05\x62\xd9\x8e\x9d\x2c\x0d\xda\x8b\x22\xed\x45\xb0\xb6\xcb\xb6\x6c\xbb\x18\x06\x81\x26\x8f\x24\x22\x14\x49\x1c\x52\x4e\x8c\xa2\xff\xfd\x05\x29\x59\xb6\x1c\x3a\x49\xf1\x36\x37\x82\xc3\xf3\xf1\x1c\x9e\xaf\x87\x6b\x46\x92\xad\x14\xc2\x09\x57\x8d\xf3\x48\xb9\x66\x35\x9e\xc0\x8f\x11\x80\x40\xc7\x49\x5a\x2f\x8d\x86\x8f\x70\x72\xdd\x0a\x40\x14\x18\x01\xf8\x8d\x45\xe8\xfe\x3e\x82\xf3\x24\x75\x39\xfa\x39\x1a\xed\x4c\x32\x2b\x73\x87\xb4\x46\x72\x49\x8b\x5f\xa5\xf3\x60\x0a\x10\xa6\x66\x52\x47\xc3\x0e\x1a\x87\x02\xbc\x01\x42\xc6\x2b\xb8\x6f\x56\x38\x61\x56\xb6\x66\xa0\x20\x53\xc3\x83\xf4\x95\xd4\xe0\x2b\x84\x0e\xf4\x53\x38\x4a\x3a\x3f\x6e\x31\xbd\x0b\xa0\xde\xc0\x7f\x2b\xd4\xa0\x8d\x07\x87\xfe\x34\x2a\xaf\x99\x6a\x30\xf8\x5f\x33\xca\xf6\xb0\xc2\x83\x54\x0a\x56\x18\xa1\x64\xe9\x78\x72\x7c\xf4\x48\x9a\xa9\xdf\x19\x18\xd3\xb0\x35\x0b\x1a\xfd\x83\xa1\xfb\x17\x22\x0b\x9e\x0b\xd6\x28\xdf\x1d\xfe\xef\xff\x47\x33\x90\x4b\xfb\x7c\x16\x98\x10\x32\xfc\x8f\x29\xb8\xb9\x5d\x2f\xc3\x6f\x42\xe7\xd0\x05\xd0\x2b\x04\xa9\xb9\x6a\x04\x0a\xe8\xee\xfe\x20\x82\xbb\xaf\xff\x02\x8e\xe4\x65\x21\x39\xf3\x89\x0a\xf9\x25\xe0\xe8\xb9\xf8\xb3\xb5\x13\x6c\x40\x67\x23\x7b\xb9\x44\xf6\x6e\xcd\x39\xf4\xb9\x90\x94\xf4\x7c\xcb\x7c\x15\x9c\x30\x10\x92\x90\x7b\x43\x1b\x78\xa8\x90\x10\x4a\xd4\x48\xcc\xa3\x80\x68\xc1\x81\xab\x4c\xa3\x44\xb8\x3c\xab\x18\x47\x01\x63\x6e\xb4\x67\x52\x3b\x70\xc8\x09\xbd\x7b\xf7\xba\x4e\xe2\xca\x34\x22\xb7\x64\xd6\x52\x60\x1a\xd6\x5d\x85\xb0\x15\x80\xc2\x10\x44\x9d\x18\xbf\xe4\xe8\x60\x8c\xb5\xf5\x9b\xce\x7a\x14\xd0\xa6\x57\x38\x0e\xe3\x30\x51\x27\x27\x43\x64\x5d\x9d\xe6\xb5\x6f\xd2\x53\xe3\xfb\x0d\x48\xed\x91\x0a\xc6\x11\xbe\xdd\xfd\xfb\xa9\x27\xdd\xd4\x2b\xa4\x27\x9e\xe6\xe7\xb3\x59\xda\x17\x6a\xce\xac\x6b\x14\x0b\x4e\x92\x5e\xbf\xb7\x92\x30\x90\x84\xda\x08\x04\x94\xbe\x42\x02\x69\xa5\x05\x43\xb0\x7e\x54\x4c\xc3\xd8\x68\xb5\x01\x66\xad\x92\x6d\xbd\x73\xa6\x24\x37\xbf\x70\x2d\xc1\xde\x91\xab\x91\x36\x67\x8d\x37\x02\x3d\xf2\x80\x23\xaf\xd1\x57\x46\x24\x81\x7f\x8b\x47\xb1\xbc\x7a\x95\xd8\x6d\x95\x71\x7e\xd0\x97\xbf\x01\x73\x21\xc9\xf9\x49\x61\x1a\x2d\x0e\xa0\x5b\x23\x72\x2e\x45\xba\xd2\xae\x6f\x3e\xff\x13\x6e\x6e\x81\x98\x2e\x31\x42\x75\x4e\x96\x1a\xfe\xd6\xac\x90\x34\x7a\x74\x60\x8d\x70\xaf\xc7\x31\x9f\x65\x67\xd9\x2c\x9b\x4d\xe7\x17\x07\x38\xba\xea\x3d\x8a\xe5\xc3\x87\x2f\x7f\xff\x3c\x7a\x05\xa0\x6d\x1b\x64\xa3\xd0\x27\xf3\x78\x97\xfd\x9c\x27\x8c\x53\x42\xc4\xae\x08\x63\x2d\xef\xc7\x5a\xbb\x29\xe6\x33\x5f\x3d\xab\x30\x11\xda\x65\xa3\x80\x65\xb4\x17\x75\x22\xe2\x36\xda\x45\x8c\xf6\x6c\x79\x72\xd8\xe5\xed\x0a\x6e\x67\x5a\xee\x9a\xa2\x90\x8f\xc9\x14\xfc\xa3\x41\x0a\x59\x0f\xfe\x5b\x69\x17\xd7\x62\x44\xdb\xea\xf5\x60\x99\x76\x0f\x48\x28\x60\xb5\xe9\xb1\xbe\x3e\x37\x1d\xa6\x4c\x19\xce\xd4\x21\xde\x76\x98\x21\xe5\x8c\x78\x95\x04\xfa\x89\x78\x25\x43\x11\x37\xd4\x03\x0b\xa0\xe3\xf2\xde\xaa\x83\xac\x59\x19\x7e\x13\x0a\xed\xa6\xdd\xf7\xaa\xfb\x4e\x60\x8c\x59\x99\x9d\x02\xa3\xfa\x62\xf9\x0b\xe5\xcd\x6a\x71\xf1\xe4\x8a\x7b\xc8\xd1\x67\x7a\xb7\x5c\x0f\x81\xc5\xe6\x6a\x1c\xc2\xb8\x45\x1d\x51\x01\x6a\x1f\x06\x7f\xb8\xe4\x12\x3d\x4c\xde\xbe\xfd\x11\x78\xc4\xf0\x4e\x7e\x86\xfe\x44\x2d\x50\x24\x70\xd7\xcc\xf6\xfb\x67\x50\x22\x01\x12\x74\xed\x0c\x4f\xfe\x42\x52\xe2\xd1\x54\x1b\x81\x57\xeb\x45\x36\x5f\x64\x8b\x93\x3d\x9d\x9c\x6b\x79\x4c\x87\x6b\x99\x56\x31\xda\x93\x51\x2a\xf0\x9f\x03\x95\x58\x34\x7b\xe7\x43\xfd\x6a\x63\x91\x82\xc8\x53\x98\xf7\x97\x2e\x2b\x39\x65\xd2\x4c\x7b\xa9\xab\xf5\x3c\x9b\x5f\xf6\xce\xbb\xcb\x4c\xc5\x78\xa4\x1a\x5a\xc5\x38\xa0\x2a\xe4\xf7\xd6\xc4\xed\xb2\xef\x55\xea\xb5\x51\xf7\x53\x6b\xc4\x64\x5f\xe4\xea\x72\x81\x67\xe7\x78\xfe\xfe\xe2\x72\xf1\x7e\xbe\x7a\x8f\xab\xc5\xf2\x6c\xb6\x3c\xe3\xcb\xc5\xb9\x98\xaf\x16\x88\x42\xac\xce\x56\x38\x6f\x3d\x0c\xe7\xc0\xb1\xb8\x86\x24\x68\x18\x5c\xb4\xb0\xbb\xb7\xbc\x66\x9a\x95\x48\x29\x0b\x3b\xa9\x49\x27\x95\x30\xe5\x78\x85\xa2\x51\x2f\x80\xe9\xa5\x12\x16\x2c\x99\xc7\xcd\x73\x69\x8a\x16\xa2\xd4\xbe\xf6\xcf\x03\x6e\xa6\xc3\x37\x27\xb4\x86\xbc\xd4\x65\xdb\x43\xc3\xda\x5e\x19\xa3\x9e\x36\xd6\x97\xa8\x09\x8d\x0b\xed\x6e\x08\x98\x66\x6a\xe3\x25\x77\xd0\x1b\x8b\xbd\x66\x9d\x27\x64\x35\x70\x53\x5b\xa3\x51\x7b\x30\x0f\x3a\x54\xe6\xf8\x4e\x96\x48\xec\x0a\xae\x77\xbb\x6e\xd8\xf5\x05\x53\x0e\x87\x78\x3d\x85\x11\x26\xf2\xc0\x4e\xdd\x8b\xb4\x2e\xf4\xf8\x8e\xd8\x19\xbd\x7d\x63\x40\xe8\x36\xd7\x31\xbd\x68\xb2\xa7\xbc\x0e\x18\x21\xdc\xa3\xf5\xaf\x1f\x4e\xd3\xc6\xd1\xd4\x55\x8c\x70\xca\xd9\x64\x8f\x38\xbb\xc3\x89\x15\x51\xaf\x99\x92\x42\xfa\x4d\x6e\x91\xa4\x11\x79\x65\x9a\x23\xc4\xf8\x3f\x9d\x64\xa4\xf4\x4a\xb5\x93\x76\xcf\x7c\xa0\xef\xad\xf6\x6b\x89\xd8\xe5\x5f\x2f\x66\xc9\x0a\x60\x65\x49\x58\x1e\x67\x61\x5d\xba\x03\x82\xbd\x55\xfc\x69\xa7\x05\x5f\xd9\x06\x09\xc6\x9d\xbf\x38\x68\x63\x02\x4f\x81\x90\x9b\xba\x3e\x36\x3a\xfb\xf2\x4a\xa6\xfe\x0d\x34\xda\x14\x85\xe4\x92\xa9\x53\xf0\x58\x5b\x43\x8c\x36\xa7\x50\xb3\x4d\xbb\xbe\x6b\x13\xb6\x77\xd8\x98\xa6\xf1\xe1\x55\x28\x39\x0e\x02\xec\x9e\x61\xbb\x01\x90\x87\xfa\x4c\x47\xb9\x7d\xb2\x1d\x3c\x88\x82\x42\xbb\xba\xe0\x62\xb9\x5c\x84\xd8\x6a\xe6\x79\xd5\xd2\xe1\x23\x0a\x89\x58\x8f\x64\x25\xd8\x3c\xc8\xca\xa3\x35\x0e\x73\xa3\x73\xa6\x54\xde\x93\xee\x74\x99\xdc\x14\xa1\x88\xf1\xf4\x10\xc4\x96\x35\xb4\xc6\x44\x68\x80\x50\x45\xbb\x01\x15\xfb\x60\x47\xe9\x5d\x90\x88\xa1\x06\x40\x19\xdc\x14\xdb\x0c\x4a\x9f\x30\xa6\x42\x4b\xb5\x6f\x47\x85\xfe\x2f\xae\xb5\x76\x73\x9b\x78\x9f\x3d\x9f\xe3\x5d\xd8\x42\xba\x58\x8d\x0e\x55\x91\x07\x9a\x8c\x22\xef\xec\x27\x23\xff\xdc\xca\xb7\x54\x09\x55\x01\xad\xce\x16\x13\x48\xed\x3c\x53\xaa\x25\x4c\x9d\xf7\x23\xe8\x06\x38\x86\x0b\x23\xc7\x47\x4f\x2c\x2f\x14\x2b\xd3\x09\xf8\x12\xce\x21\x9e\x83\x0d\xef\xc5\xc8\xfa\x03\xa0\xc9\x1e\xa0\x5d\x66\x5e\x7a\xc1\x26\x5f\xd4\x7f\x04\x00\x00\xff\xff\x4b\x09\xf1\x89\xdf\x11\x00\x00"),
 		},
 		"/lokomotive-kubernetes/bootkube/versions.tf": &vfsgen۰CompressedFileInfo{
 			name:             "versions.tf",
@@ -5606,7 +5599,6 @@ var vfsgenAssets = func() http.FileSystem {
 		fs["/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/ipamconfigs.yaml"].(os.FileInfo),
 		fs["/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/ipamhandles.yaml"].(os.FileInfo),
 		fs["/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/ippools.yaml"].(os.FileInfo),
-		fs["/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/kubecontrollersconfigurations.yaml"].(os.FileInfo),
 		fs["/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/networkpolicies.yaml"].(os.FileInfo),
 		fs["/lokomotive-kubernetes/bootkube/resources/charts/calico/crds/networksets.yaml"].(os.FileInfo),
 	}
diff --git a/pkg/components/prometheus-operator/component.go b/pkg/components/prometheus-operator/component.go
index d8add54f..137b997f 100644
--- a/pkg/components/prometheus-operator/component.go
+++ b/pkg/components/prometheus-operator/component.go
@@ -22,6 +22,7 @@ import (
 	"github.com/pkg/errors"
 
 	"github.com/kinvolk/lokomotive/pkg/components"
+	"github.com/kinvolk/lokomotive/pkg/components/types"
 	"github.com/kinvolk/lokomotive/pkg/components/util"
 )
 
@@ -45,10 +46,17 @@ type CoreDNS struct {
 	Selector map[string]string `hcl:"selector,optional"`
 }
 
+// Grafana object collects sub component grafana related information.
+type Grafana struct {
+	AdminPassword string         `hcl:"admin_password,optional"`
+	Ingress       *types.Ingress `hcl:"ingress,block"`
+}
+
 type component struct {
-	GrafanaAdminPassword string   `hcl:"grafana_admin_password,attr"`
-	Namespace            string   `hcl:"namespace,optional"`
-	EtcdEndpoints        []string `hcl:"etcd_endpoints,optional"`
+	Grafana *Grafana `hcl:"grafana,block"`
+
+	Namespace     string   `hcl:"namespace,optional"`
+	EtcdEndpoints []string `hcl:"etcd_endpoints,optional"`
 
 	PrometheusOperatorNodeSelector map[string]string `hcl:"prometheus_operator_node_selector,optional"`
 
@@ -120,11 +128,20 @@ func newComponent() *component {
 
 func (c *component) LoadConfig(configBody *hcl.Body, evalContext *hcl.EvalContext) hcl.Diagnostics {
 	if configBody == nil {
-		return hcl.Diagnostics{
-			components.HCLDiagConfigBodyNil,
-		}
+		// return empty struct instead of hcl.Diagnostics{components.HCLDiagConfigBodyNil}
+		// since all the component values are optional
+		return hcl.Diagnostics{}
+	}
+
+	if err := gohcl.DecodeBody(*configBody, evalContext, c); err != nil {
+		return err
+	}
+
+	if c.Grafana != nil && c.Grafana.Ingress != nil {
+		c.Grafana.Ingress.SetDefaults()
 	}
-	return gohcl.DecodeBody(*configBody, evalContext, c)
+
+	return nil
 }
 
 func (c *component) RenderManifests() (map[string]string, error) {
diff --git a/pkg/components/prometheus-operator/template.go b/pkg/components/prometheus-operator/template.go
index fdcda28d..f4f13165 100644
--- a/pkg/components/prometheus-operator/template.go
+++ b/pkg/components/prometheus-operator/template.go
@@ -46,8 +46,8 @@ alertmanager:
           resources:
             requests:
               storage: "{{.AlertManagerStorageSize}}"
+
 grafana:
-  adminPassword: {{.GrafanaAdminPassword}}
   plugins: "grafana-piechart-panel"
   testFramework:
     enabled: false
@@ -56,6 +56,24 @@ grafana:
       searchNamespace: ALL
   rbac:
     pspUseAppArmor: false
+  {{ if .Grafana}}
+  adminPassword: {{.Grafana.AdminPassword}}
+  {{ if .Grafana.Ingress }}
+  ingress:
+    enabled: true
+    annotations:
+      kubernetes.io/ingress.class: {{.Grafana.Ingress.Class}}
+      kubernetes.io/tls-acme: "true"
+      cert-manager.io/cluster-issuer: {{.Grafana.Ingress.CertManagerClusterIssuer}}
+    hosts:
+    - {{ .Grafana.Ingress.Host }}
+    tls:
+    - hosts:
+      - {{ .Grafana.Ingress.Host }}
+      secretName: {{ .Grafana.Ingress.Host }}-tls
+  {{ end }}
+  {{ end }}
+
 kubeEtcd:
   enabled: {{.Monitor.Etcd}}
   endpoints: {{.EtcdEndpoints}}
diff --git a/pkg/components/types/types.go b/pkg/components/types/types.go
new file mode 100644
index 00000000..ae4d0280
--- /dev/null
+++ b/pkg/components/types/types.go
@@ -0,0 +1,41 @@
+// Copyright 2020 The Lokomotive Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package types contains common types used by the components. This helps in ensuring that, all the
+// components expose same set of variables to the user to do similar tasks.
+package types
+
+const (
+	defaultIngressClass             = "contour"
+	defaultCertManagerClusterIssuer = "letsencrypt-production"
+)
+
+// Ingress is a generic object for specifying Kubernetes ingress manifest.
+type Ingress struct {
+	Host                     string `hcl:"host"`
+	Class                    string `hcl:"class,optional"`
+	CertManagerClusterIssuer string `hcl:"certmanager_cluster_issuer,optional"`
+}
+
+// SetDefaults sets default values for Ingress object only when user has not provided any
+// information.
+func (ing *Ingress) SetDefaults() {
+	if ing.Class == "" {
+		ing.Class = defaultIngressClass
+	}
+
+	if ing.CertManagerClusterIssuer == "" {
+		ing.CertManagerClusterIssuer = defaultCertManagerClusterIssuer
+	}
+}


Test patch:
diff --git a/examples/aks-testing/cluster.lokocfg b/examples/aks-testing/cluster.lokocfg
index 22d3b64d..98ce047d 100644
--- a/examples/aks-testing/cluster.lokocfg
+++ b/examples/aks-testing/cluster.lokocfg
@@ -1,6 +1,5 @@
 variable "subscription_id" {}
 variable "tenant_id" {}
-variable "grafana_admin_password" {}
 variable "resource_group_name" {}
 variable "cert_manager_email" {}
 
@@ -50,7 +49,6 @@ cluster "aks" {
 }
 
 component "prometheus-operator" {
-  grafana_admin_password = var.grafana_admin_password
   disable_webhooks       = true
 
   monitor {
diff --git a/examples/aws-testing/cluster.lokocfg b/examples/aws-testing/cluster.lokocfg
index f5fe7b0a..be01b3ec 100644
--- a/examples/aws-testing/cluster.lokocfg
+++ b/examples/aws-testing/cluster.lokocfg
@@ -1,7 +1,6 @@
 variable "dns_zone" {}
 variable "route53_zone_id" {}
 variable "ssh_public_keys" {}
-variable "grafana_admin_password" {}
 
 variable "asset_dir" {
   default = "./lokomotive-assets"
@@ -51,6 +50,4 @@ component "openebs-storage-class" {
   }
 }
 
-component "prometheus-operator" {
-  grafana_admin_password = var.grafana_admin_password
-}
+component "prometheus-operator" {}
diff --git a/examples/packet-testing/cluster.lokocfg b/examples/packet-testing/cluster.lokocfg
index c7b40e2e..b308047a 100644
--- a/examples/packet-testing/cluster.lokocfg
+++ b/examples/packet-testing/cluster.lokocfg
@@ -3,7 +3,6 @@ variable "route53_zone_id" {}
 variable "packet_project_id" {}
 variable "ssh_public_keys" {}
 variable "cert_manager_email" {}
-variable "grafana_admin_password" {}
 variable "metallb_address_pool" {}
 
 variable "asset_dir" {
@@ -90,8 +89,6 @@ component "openebs-storage-class" {
   }
 }
 
-component "prometheus-operator" {
-  grafana_admin_password = var.grafana_admin_password
-}
+component "prometheus-operator" {}
 
 component "flatcar-linux-update-operator" {}
diff --git a/pkg/components/prometheus-operator/component_test.go b/pkg/components/prometheus-operator/component_test.go
index 4733bad3..a69c35e7 100644
--- a/pkg/components/prometheus-operator/component_test.go
+++ b/pkg/components/prometheus-operator/component_test.go
@@ -17,46 +17,80 @@ package prometheus
 import (
 	"testing"
 
-	"github.com/hashicorp/hcl/v2"
-
 	"github.com/kinvolk/lokomotive/pkg/components/util"
 )
 
-func TestEmptyConfig(t *testing.T) {
-	c := newComponent()
-	emptyConfig := hcl.EmptyBody()
-	evalContext := hcl.EvalContext{}
-	diagnostics := c.LoadConfig(&emptyConfig, &evalContext)
-	if !diagnostics.HasErrors() {
-		t.Fatalf("Empty config should return error")
-	}
-}
-
+// nolint:funlen
 func TestRenderManifest(t *testing.T) {
-	configHCL := `
+	tests := []struct {
+		desc    string
+		hcl     string
+		wantErr bool
+	}{
+		{
+			desc: "essential values only",
+			hcl: `
 component "prometheus-operator" {
-  grafana_admin_password = "foo"
-  namespace              = "monitoring"
-}
-`
+  grafana {
+    admin_password = "foobar"
+  }
+  namespace = "monitoring"
+}`,
+		},
+		{
+			desc: "no values",
+			hcl:  `component "prometheus-operator" {}`,
+		},
+		{
+			desc: "ingress and host given",
+			hcl: `
+component "prometheus-operator" {
+  grafana {
+    ingress {
+	  host = "foobar"
+	}
+  }
+}`,
+		},
+		{
+			desc: "ingress and no host given",
+			hcl: `
+component "prometheus-operator" {
+  grafana {
+    ingress {}
+  }
+}`,
+			wantErr: true,
+		},
+	}
 
-	component := newComponent()
+	for _, tc := range tests {
+		tc := tc
+		t.Run(tc.desc, func(t *testing.T) {
+			b, d := util.GetComponentBody(tc.hcl, name)
+			if d != nil {
+				t.Fatalf("error getting component body: %v", d)
+			}
 
-	body, diagnostics := util.GetComponentBody(configHCL, name)
-	if diagnostics != nil {
-		t.Fatalf("Error getting component body: %v", diagnostics)
-	}
+			c := newComponent()
+			d = c.LoadConfig(b, nil)
 
-	diagnostics = component.LoadConfig(body, &hcl.EvalContext{})
-	if diagnostics.HasErrors() {
-		t.Fatalf("Valid config should not return error, got: %s", diagnostics)
-	}
+			if !tc.wantErr && d.HasErrors() {
+				t.Fatalf("valid config should not return error, got: %s", d)
+			}
 
-	m, err := component.RenderManifests()
-	if err != nil {
-		t.Fatalf("Rendering manifests with valid config should succeed, got: %s", err)
-	}
-	if len(m) <= 0 {
-		t.Fatalf("Rendered manifests shouldn't be empty")
+			if tc.wantErr && !d.HasErrors() {
+				t.Fatal("wrong config should have returned an error")
+			}
+
+			m, err := c.RenderManifests()
+			if err != nil {
+				t.Fatalf("rendering manifests with valid config should succeed, got: %s", err)
+			}
+
+			if len(m) == 0 {
+				t.Fatal("rendered manifests shouldn't be empty")
+			}
+		})
 	}
 }