Add state to control rbac

Change-Id: Ie6ae4d9bc5a91f2609ab9206d41d469a4594abc8
diff --git a/README.rst b/README.rst
index b0b8e7d..7f4dedc 100644
--- a/README.rst
+++ b/README.rst
@@ -1073,6 +1073,79 @@
           value: one
         image_pull_secretes: password
 
+Role-based access control
+=========================
+
+To enable RBAC, you need to set following option on your apiserver:
+
+.. code-block:: yaml
+
+    kubernetes:
+      master:
+        auth:
+          mode: RBAC
+
+Then you can use ``kubernetes.control.role`` state to orchestrate role and
+rolebindings. Following example shows how to create brand new role and binding
+for service account:
+
+.. code-block:: yaml
+
+    control:
+      role:
+        etcd-operator:
+          kind: ClusterRole
+          rules:
+            - apiGroups:
+                - etcd.coreos.com
+              resources:
+                - clusters
+              verbs:
+                - "*"
+            - apiGroups:
+                - extensions
+              resources:
+                - thirdpartyresources
+              verbs:
+                - create
+            - apiGroups:
+                - storage.k8s.io
+              resources:
+                - storageclasses
+              verbs:
+                - create
+            - apiGroups:
+                - ""
+              resources:
+                - replicasets
+              verbs:
+                - "*"
+          binding:
+            etcd-operator:
+              kind: ClusterRoleBinding
+              namespace: test # <-- if no namespace, then it's clusterrolebinding
+              subject:
+                etcd-operator:
+                  kind: ServiceAccount
+
+Simplest possible use-case, add user test edit permissions on it's test
+namespace:
+
+.. code-block:: yaml
+
+    kubernetes:
+      control:
+        role:
+          edit:
+            kind: ClusterRole
+            # No rules defined, so only binding will be created assuming role
+            # already exists
+            binding:
+              test:
+                namespace: test
+                subject:
+                  test:
+                    kind: User
 
 More Information
 ================
diff --git a/kubernetes/control/init.sls b/kubernetes/control/init.sls
index ea56c42..be31c21 100644
--- a/kubernetes/control/init.sls
+++ b/kubernetes/control/init.sls
@@ -1,6 +1,5 @@
 {% from "kubernetes/map.jinja" import control with context %}
 include:
-  - kubernetes.control.cluster
   {%- if control.job is defined %}
   - kubernetes.control.job
   {%- endif %}
@@ -10,6 +9,9 @@
   {%- if control.configmap is defined %}
   - kubernetes.control.configmap
   {%- endif %}
+  {%- if control.role is defined %}
+  - kubernetes.control.role
+  {%- endif %}
 
 /srv/kubernetes:
   file.directory:
diff --git a/kubernetes/control/role.sls b/kubernetes/control/role.sls
new file mode 100644
index 0000000..ce7248d
--- /dev/null
+++ b/kubernetes/control/role.sls
@@ -0,0 +1,56 @@
+{% from "kubernetes/map.jinja" import control with context %}
+include:
+  - kubernetes.control
+
+{%- for role_name, role in control.role.iteritems() %}
+  {%- set role_name = role.name|default(role_name) %}
+
+  {%- if role.get('namespace') or role.get('kind') == 'Role' %}
+    {%- set role_kind = 'Role' %}
+  {%- else %}
+    {%- set role_kind = 'ClusterRole' %}
+  {%- endif %}
+
+  {%- if role.enabled|default(True) %}
+
+    {%- if role.get('rules') %}
+/srv/kubernetes/roles/{{ role_name }}/{{ role_name }}-role.yml:
+  file.managed:
+  - source: salt://kubernetes/files/role.yml
+  - template: jinja
+  - makedirs: true
+  - require:
+    - file: /srv/kubernetes
+  - defaults:
+      role_name: {{ role_name }}
+      role_kind: {{ role_kind }}
+      role: {{ role|yaml }}
+    {%- endif %}
+
+    {%- for binding_name, binding in role.get('binding', {}).iteritems() %}
+      {%- set binding_name = binding.name|default(binding_name) %}
+      {%- if binding.get('namespace') or binding.get('kind') == 'RoleBinding' %}
+        {%- set binding_kind = 'RoleBinding' %}
+      {%- else %}
+        {%- set binding_kind = 'ClusterRoleBinding' %}
+      {%- endif %}
+
+/srv/kubernetes/roles/{{ role_name }}/{{ binding_name }}-rolebinding.yml:
+  file.managed:
+  - source: salt://kubernetes/files/rolebinding.yml
+  - template: jinja
+  - makedirs: true
+  - require:
+    - file: /srv/kubernetes
+  - defaults:
+      role_name: {{ role_name }}
+      role_kind: {{ role_kind }}
+      role: {{ role|yaml }}
+      binding_name: {{ binding_name }}
+      binding_kind: {{ binding_kind }}
+      binding: {{ binding|yaml }}
+
+    {%- endfor %}
+
+  {%- endif %}
+{%- endfor %}
diff --git a/kubernetes/files/role.yml b/kubernetes/files/role.yml
new file mode 100644
index 0000000..335a5e5
--- /dev/null
+++ b/kubernetes/files/role.yml
@@ -0,0 +1,17 @@
+kind: {{ role_kind }}
+apiVersion: rbac.authorization.k8s.io/v1beta1
+metadata:
+  {%- if role.get('namespace') %}
+  namespace: {{ role.namespace }}
+  {%- endif %}
+  name: {{ role_name }}
+{%- if role.get('rules') %}
+rules:
+  {%- for rule in role.rules %}
+  - {{ rule|yaml|indent(2) }}
+  {%- endfor %}
+{%- endif %}
+
+{#-
+vim: syntax=jinja
+-#}
diff --git a/kubernetes/files/rolebinding.yml b/kubernetes/files/rolebinding.yml
new file mode 100644
index 0000000..1befc8d
--- /dev/null
+++ b/kubernetes/files/rolebinding.yml
@@ -0,0 +1,21 @@
+kind: {{ binding_kind }}
+apiVersion: rbac.authorization.k8s.io/v1beta1
+metadata:
+  name: {{ binding_name }}
+  {%- if binding.get('namespace') %}
+  namespace: {{ binding.namespace }}
+  {%- endif %}
+subjects:
+  {%- for subject_name, subject in binding.subject.iteritems() %}
+  - kind: {{ subject.kind }}
+    name: {{ subject.name|default(subject_name) }}
+    apiGroup: rbac.authorization.k8s.io
+  {%- endfor %}
+roleRef:
+  kind: {{ role_kind }}
+  name: {{ role_name }}
+  apiGroup: rbac.authorization.k8s.io
+
+{#-
+vim: syntax=jinja
+-#}