github.com/operator-framework/operator-lifecycle-manager@v0.30.0/doc/design/scoped-operator-install.md (about)

     1  ## Background
     2  OLM runs with `cluster-admin` privileges. By default, operator author can specify any set of permission(s) in the `CSV` and OLM will consequently grant it to the operator. In effect, an operator can achieve `cluster-scoped` privilege(s) which may not always be desired.
     3  
     4  OLM introduced a new feature that applies principle of attenuation to the operator being installed. The administrator can specify a service account with a set of privilege(s) granted to it. OLM will ensure that when an operator is installed its privileges are confined to that of the service account specified.
     5  
     6  As a result a `cluster-admin` can limit an Operator to a pre-defined set of RBAC rules. The Operator will not be able to do anything that is not explicitly permitted by those. This enables self-sufficient installation of Operators by non-`cluster-admin` users with a limited scope.
     7  
     8  The section below describes how an administrator can achieve this.
     9  
    10  ### Scoped Operator Install
    11  We will cover the following scenario - an administrator wants to confine a set of operator(s) to a designated namespace.
    12  
    13  Execute the following steps to achieve this.
    14  
    15  * Create a new namespace.
    16  ```bash
    17  cat <<EOF | kubectl create -f -
    18  apiVersion: v1
    19  kind: Namespace
    20  metadata:
    21    name: scoped
    22  EOF
    23  ```
    24  
    25  * Allocate permission(s) that you want the operator(s) to be confined to. This involves creating a new `ServiceAccount`, relevant `Role(s)` and `RoleBinding(s)`.
    26  
    27  ```bash
    28  cat <<EOF | kubectl create -f -
    29  apiVersion: v1
    30  kind: ServiceAccount
    31  metadata:
    32    name: scoped
    33    namespace: scoped
    34  EOF
    35  ```
    36  
    37  Since this is an exercise I am granting the `ServiceAccount` permission(s) to do anything in the designated namespace for simplicity. In real life we would create a more fine grained set of permission(s).
    38  
    39  ```bash
    40  cat <<EOF | kubectl create -f -
    41  apiVersion: rbac.authorization.k8s.io/v1
    42  kind: Role
    43  metadata:
    44    name: scoped
    45    namespace: scoped
    46  rules:
    47  - apiGroups: ["*"]
    48    resources: ["*"]
    49    verbs: ["*"]  
    50  ---
    51  apiVersion: rbac.authorization.k8s.io/v1
    52  kind: RoleBinding
    53  metadata:
    54    name: scoped-bindings
    55    namespace: scoped
    56  roleRef:
    57    apiGroup: rbac.authorization.k8s.io
    58    kind: Role
    59    name: scoped
    60  subjects:
    61  - kind: ServiceAccount
    62    name: scoped
    63    namespace: scoped
    64  EOF
    65  ```
    66  
    67  * Create an `OperatorGroup` in the designated namespace. This operator group targets the designated namespace to ensure that its tenancy is confined to it. In addition, `OperatorGroup` allows a user to specify a `ServiceAccount`. We will specify the `ServiceAccount` we created above. 
    68  
    69  ```bash
    70  cat <<EOF | kubectl create -f -
    71  apiVersion: operators.coreos.com/v1
    72  kind: OperatorGroup
    73  metadata:
    74    name: scoped
    75    namespace: scoped
    76  spec:
    77    serviceAccountName: scoped
    78    targetNamespaces:
    79    - scoped
    80  EOF
    81  ```
    82  
    83  Any operator being installed in the designated namespace will now be tied to this `OperatorGroup` and hence to the `ServiceAccount` specified. 
    84  
    85  * Create a subscription in the designated namespace to install an operator. You can specify a `CatalogSource` that already exists in the designated namespace, or one that is in the global catalog namespace.
    86  ```bash
    87  cat <<EOF | kubectl create -f -
    88  apiVersion: operators.coreos.com/v1alpha1
    89  kind: Subscription
    90  metadata:
    91    name: etcd
    92    namespace: scoped
    93  spec:
    94    channel: singlenamespace-alpha
    95    name: etcd
    96    source: operatorhubio-catalog
    97  EOF
    98  ```
    99  Any operator tied to this `OperatorGroup` will now be confined to the permission(s) granted to the specified `ServiceAccount`. If the operator asks for permission(s) that are outside the scope of the `ServiceAccount` the install will fail with appropriate error(s). When OLM installs the operator the following will happen:
   100  * The given `Subscription` object is picked up by OLM.
   101  * OLM fetches the `OperatorGroup` tied to this subscription.
   102  * OLM determines that the `OperatorGroup` has a `ServiceAccount` specified.
   103  * OLM creates a `client` scoped to the `ServiceAccount` and uses the scoped client to install the operator. This ensures that any permission requested by the operator is always confined to that of the `ServiceAccount` in `OperatorGroup`.
   104  * OLM creates a new `ServiceAccount` with the set of permission(s) specified in the `csv` and assigns it to the operator. The operator runs as the assigned `ServiceAccount`. 
   105  
   106  
   107  ## When Operator Install Fails
   108  If the operator install fails due to lack of permission(s), follow the steps below to identify the error(s).
   109  * Start with the `Subscription` object, its `status` has an object reference `installPlanRef` that points to the `InstallPlan` object that attempted to create the necessary `[Cluster]Role[Binding](s)` for the operator.
   110  ```
   111  apiVersion: operators.coreos.com/v1alpha1
   112  kind: Subscription
   113  metadata:
   114    name: etcd
   115    namespace: scoped
   116  status:
   117    installPlanRef:
   118      apiVersion: operators.coreos.com/v1alpha1
   119      kind: InstallPlan
   120      name: install-4plp8
   121      namespace: scoped
   122      resourceVersion: "117359"
   123      uid: 2c1df80e-afea-11e9-bce3-5254009c9c23
   124  ```
   125  
   126  * Check the status of the `InstallPlan` object, it will depict the error OLM ran into. Here is an example:
   127  ```
   128  apiVersion: operators.coreos.com/v1alpha1
   129  kind: InstallPlan
   130  status:
   131    conditions:
   132    - lastTransitionTime: "2019-07-26T21:13:10Z"
   133      lastUpdateTime: "2019-07-26T21:13:10Z"
   134      message: 'error creating clusterrole etcdoperator.v0.9.4-clusterwide-dsfx4: clusterroles.rbac.authorization.k8s.io
   135        is forbidden: User "system:serviceaccount:scoped:scoped" cannot create resource
   136        "clusterroles" in API group "rbac.authorization.k8s.io" at the cluster scope'
   137      reason: InstallComponentFailed
   138      status: "False"
   139      type: Installed
   140    phase: Failed
   141  ```
   142  The error message will tell you:
   143  * The type of resource it failed to create, including the API group of the resource ( In this case `clusterroles` in `rbac.authorization.k8s.io` group).
   144  * The name of the resource.
   145  * The type of error - `is forbidden` tells you that the user does not have enough permission to do the operation.
   146  * The name of the user who attempted to create/update the resource, it will refer to the `ServiceAccount` we have specified in the `OperatorGroup`.
   147  * The scope of the operation, `cluster scope` or not.
   148  
   149  The user can add the missing permission to the `ServiceAccount` and then iterate. Unfortunately, OLM does not provide the complete list of error(s) on the first try. This feature will be added in the future.
   150  
   151  ## Fine Grained Permission(s)
   152  OLM uses the `ServiceAccount` specified in `OperatorGroup` to create or update the following resource(s) related to the operator being installed.
   153  * `ClusterServiceVersion`
   154  * `Subscription`
   155  * `Secret`
   156  * `ServiceAccount`
   157  * `Service`
   158  * `ClusterRole` and `ClusterRoleBinding`
   159  * `Role` and `RoleBinding`
   160  
   161  In order to confine operator(s) to a designated namespace the administrator can start by granting the following permission(s) to the `ServiceAccount`.
   162  ```
   163  kind: Role
   164  rules:
   165  - apiGroups: ["operators.coreos.com"]
   166    resources: ["subscriptions", "clusterserviceversions"]
   167    verbs: ["get", "create", "update", "patch"]
   168  - apiGroups: [""]
   169    resources: ["services", "serviceaccounts"]
   170    verbs: ["get", "create", "update", "patch"]
   171  - apiGroups: ["rbac.authorization.k8s.io"]
   172    resources: ["roles", "rolebindings"]
   173    verbs: ["get", "create", "update", "patch"]
   174  
   175    # Add permission(s) to create deployment/pods and other resource(s).
   176  - apiGroups: ["apps"]
   177    resources: ["deployments"]
   178    verbs: ["list", "watch", "get", "create", "update", "patch", "delete"]
   179  - apiGroups: [""]
   180    resources: ["pods"]
   181    verbs: ["list", "watch", "get", "create", "update", "patch", "delete"]
   182  ```
   183  
   184  If any operator specifies a pull secret then the following permission needs to be added.
   185  ```
   186  # This is needed to get the secret from OLM namespace.
   187  kind: ClusterRole
   188  rules:
   189  - apiGroups: [""]
   190    resources: ["secrets"]
   191    verbs: ["get"]
   192  
   193  ---
   194  
   195  kind: Role
   196  rules:
   197  - apiGroups: [""]
   198    resources: ["secrets"]
   199    verbs: ["create", "update", "patch"]
   200  ```