k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/workload-identity/bind-service-accounts.sh (about)

     1  #!/usr/bin/env bash
     2  # Copyright 2020 The Kubernetes Authors.
     3  #
     4  # Licensed under the Apache License, Version 2.0 (the "License");
     5  # you may not use this file except in compliance with the License.
     6  # You may obtain a copy of the License at
     7  #
     8  #     http://www.apache.org/licenses/LICENSE-2.0
     9  #
    10  # Unless required by applicable law or agreed to in writing, software
    11  # distributed under the License is distributed on an "AS IS" BASIS,
    12  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  # See the License for the specific language governing permissions and
    14  # limitations under the License.
    15  
    16  
    17  set -o errexit
    18  set -o nounset
    19  set -o pipefail
    20  
    21  if [[ $# != 6 ]]; then
    22    echo "Usage: $(basename "$0") <project> <zone_or_region> <cluster> <namespace> <name> <gcp-service-account>" >&2
    23    exit 1
    24  fi
    25  
    26  # Require bash version >= 4.4
    27  if ((${BASH_VERSINFO[0]}<4)) || ( ((${BASH_VERSINFO[0]}==4)) && ((${BASH_VERSINFO[1]}<4)) ); then
    28    echo "ERROR: This script requires a minimum bash version of 4.4, but got version of ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}"
    29    if [ "$(uname)" = 'Darwin' ]; then
    30      echo "On macOS with homebrew 'brew install bash' is sufficient."
    31    fi
    32    exit 1
    33  fi
    34  
    35  project=$1
    36  zone=$2
    37  cluster=$3
    38  context="gke_${project}_${zone}_${cluster}"
    39  namespace=$4
    40  name=$5
    41  gcp_service_account=$6
    42  
    43  current-annotation() {
    44    kubectl get serviceaccounts \
    45      "--context=$context" "--namespace=$namespace" "$name" \
    46      -o jsonpath="{.metadata.annotations.iam\.gke\.io/gcp-service-account}"
    47  }
    48  
    49  current=$(current-annotation || echo MISSING)
    50  
    51  if [[ "$current" != "$gcp_service_account" ]]; then
    52    echo "Service account has wrong/missing annotation, please declare the following to $namespace/$name in $context:" >&2
    53    echo '"{"metadata": {"annotations": "iam.gke.io/gcp-service-account": '"\"$gcp_service_account\"}}"
    54    exit 1
    55  fi
    56  
    57  # Extract GOAL from someone@GOAL.iam.gserviceaccount.com
    58  gcp_sa_project=${gcp_service_account##*@}
    59  gcp_sa_project=${gcp_sa_project%%.*}
    60  
    61  # Default compute engine service accounts have a different format that makes them
    62  # appear to belong to a 'developer' project:  <project-number>-compute@developer.gserviceaccount.com
    63  # We assume the default compute SA belongs to the project containing the cluster in this case.
    64  if [[ "${gcp_sa_project}" == "developer" ]]; then
    65    gcp_sa_project="${project}"
    66  fi
    67  
    68  role=roles/iam.workloadIdentityUser
    69  members=($(
    70    gcloud iam service-accounts get-iam-policy \
    71      "--project=$gcp_sa_project" "$gcp_service_account" \
    72      --filter="bindings.role=$role" \
    73      --flatten=bindings --format='value[delimiter=" "](bindings.members)'
    74  ))
    75  
    76  want="serviceAccount:$project.svc.id.goog[$namespace/$name]"
    77  fix_policy=yes
    78  for member in "${members[@]}"; do
    79    if [[ "$want" == "$member" ]]; then
    80      fix_policy=
    81      break
    82    fi
    83  done
    84  
    85  
    86  if [[ -z "${fix_policy}" ]]; then
    87      echo "ALREADY MEMBER: $want has $role for $gcp_service_account."
    88  else
    89    (
    90      set -o xtrace
    91      gcloud iam service-accounts add-iam-policy-binding \
    92        "--project=$gcp_sa_project" \
    93        --role=roles/iam.workloadIdentityUser \
    94        "--member=$want" \
    95        $gcp_service_account
    96    ) > /dev/null
    97    echo "Sleeping 2m to allow credentials to propagate.." >&2
    98    sleep 2m
    99  fi
   100  
   101  
   102  pod-identity() {
   103    head -n 1 <(
   104      entropy=$(date +%S)
   105      set -o xtrace
   106      kubectl run --rm=true -i \
   107        "--context=$context" "--namespace=$namespace" \
   108        "--overrides={\"spec\": {\"serviceAccount\": \"$name\"}}" \
   109        --image=google/cloud-sdk:slim "workload-identity-test-$entropy" \
   110        <<< "gcloud config get-value core/account"
   111    )
   112  }
   113  
   114  # Filter out the  the "try pressing enter" message from stderr
   115  got=$((pod-identity 3>&1 1>&2 2>&3 | grep -v "try pressing enter") 3>&1 1>&2 2>&3)
   116  if [[ "$got" != "$gcp_service_account" ]]; then
   117    echo "Bad identity, got $got, want $gcp_service_account" >&2
   118    exit 1
   119  fi
   120  
   121  echo "DONE: --context=$context --namespace=$namespace serviceaccounts/$name acts as $gcp_service_account"