Azure: ustalenie minimalnych uprawnień wymaganych do pewnej czynności

5-mar-2022

Zadanie z jakim się zmierzam, to ustalenie minimalnych uprawnień jakie powinien posiadać użytkownik, aby wykonać pewną czynność. W tym przypadku chodziło o budowanie specyficznej infrastruktury z wykorzystaniem skryptu Terraform, ale metoda sprawdzi się też w innych scenariuszach.

Zacząłem od stworzenia service principal, bo w moim przypadku skrypt miał być uruchamiany na service principal. Gdyby miało to być zwykłe konto użytkownika, to oczywiście należało by stworzyć konto:

az ad sp create-for-rbac --name myserviceprincipal

W wyniku tego polecenia jest tworzony service principal, a  w zwróconym output można znaleźć coś w tym stylu:

{
  "appId": "6...XXX...",
  "displayName": "myserviceprincipal",
  "password": "y...XXX...",
  "tenant": "6...XXX..."
}

Mamy tu: appId, bo jest on wykorzystywany przez dalsze polecenia i można go utożsamiać z określonym service principal i password, bo to tajna część utworzonego właśnie service principal i wreszcie tenant określający, gdzie tego service principal można używać (w jakiej organizacji).

Kiedy chcesz zalogować się z wykorzystaniem tego service principal, to można to zrobić mniej więcej tak:

az login --service-principal --username "6...XXX..." --password "y...XXX..." --tenant "6...XXX..."

Jak widać, skorzystaliśmy ze wszystkiego oprócz… nazwy service principal.

Zakładając, że konto jest „gołe”, to w/w polecenie może kończyć się błędem

No subscriptions found for 6…XXX….

Oznacza on mniej więcej tyle,  że użytkownik nie ma żadnych uprawnień na żadnej subskrypcji. Wystarczy nadać mu jakiekolwiek i problem powinien zniknąć.

Kolejny błąd jest w moim przypadku bardzo specyficzny dla mojego scenariusza. Błąd jest zwracany przez Terraforma, który narzeka, że w bieżącej sesji zalogowałem się na service principal, a tymczasem on (Terraform), na to nie pozwala. Jak chcę używać konta użytkownika to się loguję przez az login i działam, ale przy service principal, Terraform chce, żeby podać mu dane dotyczące uwierzytelnienia w postaci zmiennych środowiskowych. Oto fragment błędu:

building AzureRM Client: Authenticating using the Azure CLI is only supported as a User (not a Service Principal)

Ok. Definicja zmiennych środowiskowych może wyglądać tak:

export ARM_CLIENT_ID="6...XXX..."
export ARM_CLIENT_SECRET="y...XXX..."
export ARM_SUBSCRIPTION_ID="8...XXX..."
export ARM_TENANT_ID="6...XXX..."

dodatkowo w skrypcie terraform (main.tf) należy dodać:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=2.91.0"
    }
  }
}
provider "azurerm" {
  features {}
}

Od tej pory można już pracować „w pętli”. Kolejne uruchomienia skryptów kończą się błędami w takim stylu:

Error: retrieving Virtual Network: (Name „v…XXX…” / Resource Group „rg…XX…”): network.VirtualNetworksClient#Get: Failure responding to request: StatusCode=403 — Original Error: autorest/azure: Service returned an error. Status=403 Code=”AuthorizationFailed” Message=”The client '3…XXX…’ with object id '3…XXX…’ does not have authorization to perform action ’Microsoft.Network/virtualNetworks/read’ over scope '/subscriptions/8…XXX…/resourceGroups/rg…XXX…/providers/Microsoft.Network/virtualNetworks/v…XXX…’ or the scope is invalid. If access was recently granted, please refresh your credentials.”

Komunikat wyraźnie stwierdza jakiego uprawnienia brakuje. W tym przypadku jest to np. Microsoft.Network/virtualNetworks/read. Wystarczy więc je przyznać i potwórzyć uruchomienie skryptu, które tym razem powinno się prawdopodobnie znowu skończyć błędem, ale już innym, wskazującym na brak innego wymaganego uprawnienia.

W końcu… przy którejśtam próbie skrypt powinien się skończyć powodzeniem, a przyznane aktualnie upranienia dla service principal, będą tymi najmniejszymi jakie są potrzebne.

Warto jeszcze mieć na uwadze, że to jedno konto może być wykorzystywane do czegoś jeszcze i w takim  przypadku, te inne scenariusze użycia również należy przećwiczyć.

Tak przy okazji – ja miałem jeszcze jeden ciekawy błąd, chociaż jak się okazało nie był on powiązany z nadawaniem uprawnień:

Error: making Read request for Flexible Server Configuration: (Configuration Name „pgbouncer.enabled” / Flexible Server Name „ps..XXX…” / Resource Group „r…XXX…”): postgresqlflexibleservers.ConfigurationsClient#Get: Failure sending request: StatusCode=504 — Original Error: context deadline exceeded

O co chodziło? Ten błąd był efektem polecenia zmieniającego opcję PostgreSQL server, ale… ten serwer był wyłączony. Skrypt nie mógł się do niego połączyć i stąd dochodziło do będu context deadline exceeded. Naprawienie sytuacji to po prostu uruchomienie serwera.

Na zakończenie ostatnia uwaga. Od momentu nadania uprawnienia, do momentu kiedy można zacząć z niego korzystać mija chwila lub dwie. To czas potrzebny na rozpropagowanie informacji o uprawnieniach z AAD do obiektów, które następnie z nich korzystają. Życzę więc cierpliwości.

 

Komentarze są wyłączone

Autor: Rafał Kraik