summary refs log tree commit diff
path: root/nixos/tests/kubernetes/rbac.nix
blob: 9e73fbbd32a8f87d7fce4f4edda006583b557729 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
{ system ? builtins.currentSystem, pkgs ? import ../../.. { inherit system; } }:
with import ./base.nix { inherit system; };
let

  roServiceAccount = pkgs.writeText "ro-service-account.json" (builtins.toJSON {
    kind = "ServiceAccount";
    apiVersion = "v1";
    metadata = {
      name = "read-only";
      namespace = "default";
    };
  });

  roRoleBinding = pkgs.writeText "ro-role-binding.json" (builtins.toJSON {
    apiVersion = "rbac.authorization.k8s.io/v1";
    kind = "RoleBinding";
    metadata = {
      name = "read-pods";
      namespace = "default";
    };
    roleRef = {
      apiGroup = "rbac.authorization.k8s.io";
      kind = "Role";
      name = "pod-reader";
    };
    subjects = [{
      kind = "ServiceAccount";
      name = "read-only";
      namespace = "default";
    }];
  });

  roRole = pkgs.writeText "ro-role.json" (builtins.toJSON {
    apiVersion = "rbac.authorization.k8s.io/v1";
    kind = "Role";
    metadata = {
      name = "pod-reader";
      namespace = "default";
    };
    rules = [{
      apiGroups = [""];
      resources = ["pods"];
      verbs = ["get" "list" "watch"];
    }];
  });

  kubectlPod = pkgs.writeText "kubectl-pod.json" (builtins.toJSON {
    kind = "Pod";
    apiVersion = "v1";
    metadata.name = "kubectl";
    metadata.namespace = "default";
    metadata.labels.name = "kubectl";
    spec.serviceAccountName = "read-only";
    spec.containers = [{
      name = "kubectl";
      image = "kubectl:latest";
      command = ["/bin/tail" "-f"];
      imagePullPolicy = "Never";
      tty = true;
    }];
  });

  kubectlPod2 = pkgs.writeTextDir "kubectl-pod-2.json" (builtins.toJSON {
    kind = "Pod";
    apiVersion = "v1";
    metadata.name = "kubectl-2";
    metadata.namespace = "default";
    metadata.labels.name = "kubectl-2";
    spec.serviceAccountName = "read-only";
    spec.containers = [{
      name = "kubectl-2";
      image = "kubectl:latest";
      command = ["/bin/tail" "-f"];
      imagePullPolicy = "Never";
      tty = true;
    }];
  });

  copyKubectl = pkgs.runCommand "copy-kubectl" { } ''
    mkdir -p $out/bin
    cp ${pkgs.kubernetes}/bin/kubectl $out/bin/kubectl
  '';

  kubectlImage = pkgs.dockerTools.buildImage {
    name = "kubectl";
    tag = "latest";
    contents = [ copyKubectl pkgs.busybox kubectlPod2 ];
    config.Entrypoint = ["/bin/sh"];
  };

  base = {
    name = "rbac";
  };

  singlenode = base // {
    test = ''
      machine1.wait_until_succeeds("kubectl get node machine1.my.zyx | grep -w Ready")

      machine1.wait_until_succeeds(
          "${pkgs.gzip}/bin/zcat ${kubectlImage} | ${pkgs.containerd}/bin/ctr -n k8s.io image import -"
      )

      machine1.wait_until_succeeds(
          "kubectl apply -f ${roServiceAccount}"
      )
      machine1.wait_until_succeeds(
          "kubectl apply -f ${roRole}"
      )
      machine1.wait_until_succeeds(
          "kubectl apply -f ${roRoleBinding}"
      )
      machine1.wait_until_succeeds(
          "kubectl create -f ${kubectlPod}"
      )

      machine1.wait_until_succeeds("kubectl get pod kubectl | grep Running")

      machine1.wait_until_succeeds("kubectl exec kubectl -- kubectl get pods")
      machine1.fail("kubectl exec kubectl -- kubectl create -f /kubectl-pod-2.json")
      machine1.fail("kubectl exec kubectl -- kubectl delete pods -l name=kubectl")
    '';
  };

  multinode = base // {
    test = ''
      # Node token exchange
      machine1.wait_until_succeeds(
          "cp -f /var/lib/cfssl/apitoken.secret /tmp/shared/apitoken.secret"
      )
      machine2.wait_until_succeeds(
          "cat /tmp/shared/apitoken.secret | nixos-kubernetes-node-join"
      )

      machine1.wait_until_succeeds("kubectl get node machine2.my.zyx | grep -w Ready")

      machine2.wait_until_succeeds(
          "${pkgs.gzip}/bin/zcat ${kubectlImage} | ${pkgs.containerd}/bin/ctr -n k8s.io image import -"
      )

      machine1.wait_until_succeeds(
          "kubectl apply -f ${roServiceAccount}"
      )
      machine1.wait_until_succeeds(
          "kubectl apply -f ${roRole}"
      )
      machine1.wait_until_succeeds(
          "kubectl apply -f ${roRoleBinding}"
      )
      machine1.wait_until_succeeds(
          "kubectl create -f ${kubectlPod}"
      )

      machine1.wait_until_succeeds("kubectl get pod kubectl | grep Running")

      machine1.wait_until_succeeds("kubectl exec kubectl -- kubectl get pods")
      machine1.fail("kubectl exec kubectl -- kubectl create -f /kubectl-pod-2.json")
      machine1.fail("kubectl exec kubectl -- kubectl delete pods -l name=kubectl")
    '';
  };

in {
  singlenode = mkKubernetesSingleNodeTest singlenode;
  multinode = mkKubernetesMultiNodeTest multinode;
}