Internal Azure Load Balancer: Jak zbalansować kilka usług na jednej Backend Pool

Dzisiaj chciałbym przedstawić pewien powszechny problem z Azure Load Balancerem. Przyjmijmy następujący scenariusz:

  1. Klient posiada aplikację on-premises z load balancerem,
  2. Ta aplikacja składa się z kilku modułów,
  3. Każdy węzeł puli hostuje zestaw modułów,
  4. Niektóre moduły korzystają z usług świadczonych przez inne moduły,
  5. Moduły działają niezależnie,i używają Load Balancera jako proxy do pozostałych modułów wchodzących w skład aplikacji,
  6. Używany jest nie tylko HTTP, ale też conajmniej jeden inny protokół oparty na TCP,
  7. Klient chce przenieść infrastrukturę do Chmury Azure.

Przykład takiego scenariusza jest opisany w następującym artykule KB CyberArk: Artykuł KB CyberArk.
Microsoft opisuje ten przypadek w przewodniku po rozwiązywaniu problemów z Azure.
Możemy tam przeczytać, że:

Jeśli wirtualna sieć jest skonfigurowana z wewnętrznym load balancerem, i jeden z uczestniczących w niej węzłów backendowych próbuje uzyskać dostęp do wewnętrznego frontu load balancera, to mogą wystąpić problemy z komunikacją, gdy ruch jest mapowany z powrotem do źródłowej VM. Taki scenariusz nie jest obsługiwany.

I oczywiście, to prawda. Sprawdźmy przyczynę tego problemu.
Jak wspomniałem wcześniej, nasz klient chce przeprowadzić migrację „shift and lift” dla swojej infrastruktury CyberArk. Innymi słowy, chce użyć jak najwięcej wbudowanych usług w Chmurze. W takiej sytuacji Azure Load Balancer jest naturalnym wyborem.
Poniżej przytoczyłem przykład projektu architektonicznego CyberArk:
Architektura zawodzącego zrównoważacza obciążenia Azure

Żeby lepiej wyjaśnić przycznę problemu, najpierw przedstawię niektóre właściwości i ograniczenia Azure Load Balancera:

  1. Azure Load Balancer działa tylko na warstwie 4 modelu OSI/ISO,
  2. Azure Load Balancer działa przy użyciu standardowych metod zrównoważenia obciążenia pracy – czyli źródłowe i docelowe adresy IP oraz porty TCP,
  3. Azure Internal Load Balancer używa wirtualnego adresu IP (VIP) z sieci klienta, co pozwala na zachowanie ruchu wewnątrz vNet,
  4. Azure VM może być częścią tylko jednego wewnętrznego i jednego zewnętrznego Load Balancera,
  5. Tylko podstawowy interfejs sieciowy (vNIC) danej Azure VM może być częścią backend pool Load Balancera. Tylko ten interfejs może mieć skonfigurowaną domyślną bramę,
  6. Azure Load Balanver nie wykonuje translacji adresów IP wychodzących (SNAT). On po prostu nie ma przypisanego adresu IP wychodzącego, tylko przychodzący. Oznacza to, że Azure Load Balancer zmienia tylko adres docelowy z własnego VIP na podstawowy adres IP VMki podczas przetwarzania reguł NAT lub zrównoważania obciążenia. Z perspektywy maszyny wirtualnej w Azure, Azure Load Balancer jest całkowicie przeźroczysty i niewidoczny.

To ostatnie ograniczenie jest przyczyną naszego problemu. Microsoft stwierdza (powtórzmy to, to jest kluczowe!):

mogą wystąpić problemy z komunikacją, gdy ruch jest mapowany z powrotem do źródłowej VM

Dzieje się tak dlatego, że po opuszczeniu Azure Load Balancera pakiet IP będzie miał taki sam adres źródłowy i jak adres docelowy. Zgodnie z RFC 791, sekcja 3.2 taka sytuacja nie powinna się zdarzyć i platforma Azure odrzuca te pakiety IP jako spoofing.

Mając to na uwadze, możemy teraz spróbować znaleźć jakieś rozwiązanie. Z punktu widzenia architektury, musimy stworzyć takie warunki, gdzie adres źródłowy będzie różnił się od adresu docelowego po przejściu przez load balancer. Znaczy to tyle, że nasza maszyna wirtualna musi mieć dodatkowy adres IP.
Dodatkowe adresy IP na karcie sieciowej Azure vNic są obsługiwane w Azure, ale tylko podstawowy adres IP z danego interfejsu może być domyślnie używany jako źródło pakietu IP. Oznacza to, że nie możemy wykorzystać tej funkcji w naszym scenariuszu.
Inną możliwością jest dodanie kolejnej karty sieciowej (vNic) do VM. To również jest wspierane. Maszyna wirtualna w Azure może mieć jedną podstawową kartę sieciową i do ośmiu dodatkowych kart sieciowych. Dodatkowe karty sieciowe mogą być przypisane do dowolnej podsieci w ramach vNet podstawowej karty sieciowej. Więc maszyna wirtualna w Azure nie może należeć do więcej niż jednego vNet Azure. To nam wystarczy. Musimy utworzyć dodatkową podsieć i dołączyć do niej drugą kartę sieciową.
Dodatkowe karty sieciowe mają jeszcze jedno ograniczenie. Nie mogą mieć domyślnej trasy. W zasadzie nie mogą mieć żadnej trasy. Dodatkowe karty sieciowe mogą gromadzić ruch, ale trudno jest przez nie coś wysłać. Więc takie naiwne podejście nie będzie działać. Adres źródłowy nadal zostanie ustawiony na podstawowy adres IP karty sieciowej.

Sztuczka polega na zmianie VIP Internal Load Balancera.
To jedyny sposób na wymuszenie przesłania pakietu IP przez drugą kartę sieciową. Gdy VIP wewnętrznego Load Balancera jest z tej samej podsieci co dodatkowa karta sieciowa, możemy wykorzystać domyślne zachowanie IP – adresy IP z lokalnej sieci są osiągane poprzez lokalny segment ethernetu lub inne medium. Normalnie, to jest kwestia optymalizacji, ale w tym scenariuszu jest to nasza jedyna szansa.

Ostateczną architekturę przedstawiłem na poniższym obrazku:

Happy Load Balancing!

Konfiguracja Certyfikatu RDP na serwerze Windows 2016

Na serwerze Windows 2016, tak samo jak w wersji poprzedniej, nie ma narzędzia konfiguracyjnego umożliwiającego ustawienie certyfikatów RDP.
Można dokonać konfiguracji certyfikatu przy użyciu WMI. Najłatwiej jest tego dokonać poprzez Powershella.
Poniżej skrypt konfigurujący:

1
2
3
4
$CN = "CN=localhost"
$RdpSetting = Get-WmiObject -class "Win32_TSGeneralSetting" -Namespace root\cimv2\terminalservices -Filter "TerminalName='RDP-tcp'"
$thumbprint = (Get-ChildItem -path cert:/LocalMachine/My | | ? Subject -eq $CN).Thumbprint
Set-WmiInstance -path $RdpSetting.__path -argument @{SSLCertificateSHA1Hash="$thumbprint"}

Jest to metoda uniwersalna, działająca zarówno na systemie klienckim, jak i serwerowym.

Błąd „Root element is missing” przy wywołaniu Runbooka SMA

Najczęściej taki błąd pojawia się, gdy z poziomu bloku inline lub z funkcji wywoływany jest inny Runbook. Zachowanie takie jest niedozwolone.
Ostatnio spotkałem się z innym powodem tego błędu.
Normalnie w Powershellu możliwe jest indeksowanie tablicowe obiektu zwracanego z wyrażenia objętego nawiasami:

1
$var = (get-service)[0]

W przypadku użycia takiego wyrażenia w SMA zwracany jest właśnie błąd „Root element is missing”

Zaawansowane filtrowanie w Windows Event Log

Jest mało znanym faktem, że Event Log Viewer umożliwia filtrowanie nie tylko graficzne, ale także zaawansowane query uwzględniające dowolne dane zawarte we wpisach określonego typu.
Drugim mało znanym faktem jest, że Event Log Viewer umożliwia wyświetlenie i filtrowanie po tak zwanym „Correlation ID”. Oczywiście, aplikacja wpisująca rekordy do dziennika zdarzeń także musi wspierać Correlation ID, gdyż część aplikacji nie zapisuje tego pola.
Niezwykle przydatną sprawą jeśli chodzi o Correlation ID jest to, że możemy odfiltrować zdarzenia związane z jakąś jedną konkretną czynnością, która generuje szereg zdarzeń, zakończony, na przykład, błędem.
Oto przykładowe query:

1
2
3
4
5
6
7
<QueryList>
  <Query Id="0" Path="file://C:\Logs\Logs.evtx">
    <Select Path="file://C:\Logs\Logs.evtx">
*[System[Correlation[@ActivityID='{8A348658-802A-4ACB-A855-1CC57EA25B18}'] and (Level=1  or Level=2 or Level=3 or Level = 4) and TimeCreated[@SystemTime&gt;='2016-11-27T15:11:00.000Z' and @SystemTime&lt;='2016-11-21T15:12:00.000Z']]]
    </Select>
  </Query>
</QueryList>

Każdy wpis w logu systemu windows od 2008 w górę jest prezentowany w formacie XML. Query się odnosi do pól we wpisie. Niestety nie jest to wyrażenie XPATH, ale jest równie intuicyjne i proste do odczytania.
Przedstawiam przykładowy wpis z dziennika zdarzeń:

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
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Microsoft-Windows-GroupPolicy" Guid="{AEA1B4FA-97D1-45F2-A64C-4D69FFFD92C9}" />
    <EventID>1500</EventID>
    <Version>0</Version>
    <Level>4</Level>
    <Task>0</Task>
    <Opcode>1</Opcode>
    <Keywords>0x8000000000000000</Keywords>
    <TimeCreated SystemTime="2016-11-27T15:11:31.651603600Z" />
    <EventRecordID>31607</EventRecordID>
    <Correlation ActivityID="{8A348658-802A-4ACB-A855-1CC57EA25B18}" />
    <Execution ProcessID="1288" ThreadID="31724" />
    <Channel>System</Channel>
    <Computer>ComputerName</Computer>
    <Security UserID="S-1-5-18" />
  </System>
  <EventData>
    <Data Name="SupportInfo1">1</Data>
    <Data Name="SupportInfo2">4202</Data>
    <Data Name="ProcessingMode">0</Data>
    <Data Name="ProcessingTimeInMilliseconds">0</Data>
    <Data Name="DCName" />
  </EventData>
</Event>

Najprostszą metodą do rozpoczęcia prac nad kwerendą jest wyjście od ustalenia elementarnych warunków Filtrowania poprzez wybranie opcji „Filter Current Log”.
Poniższy wycinek ekranu pokazuje przykładowe warunki filtru.
ScreenShot1
Następnie przechodzimy na zakładkę „XML” i zaznaczamy checkbox „Edit query manually”
ScreenShot2
Po zatwierdzeniu komunikatu o fakcie, iż nie będzie można tego query już więcej edytować graficznie, otrzymujemy edytor query.
ScreenShot3
Filozofia tworzenia query jest prosta. Każdy tag, na podstawie którego będzie wykonywane filtrowanie znajduje swoje odzwierciedlenie w postaci składni:

1
Tag[Warunek1 and/or Warunek2 (...)]

Oczywiście można zagnieżdżać w wyrażeniu kolejne tagi, jak również łączyć je operatorami. Każdy wpis w logu systemowym, który spełni wszystkie warunki zostanie pokazany w odfiltrowanym widoku.
Przedstawię jeszcze raz filtr, który pojawił się na początku. Zostanie on sformatowany w trochę inny sposób, należy jednak pamiętać, że query powinno być zapisane w jednej linii.

1
2
3
4
5
6
7
8
9
10
11
12
*[
    System[
        Correlation[
            @ActivityID='{8A348658-802A-4ACB-A855-1CC57EA25B18}'
        ]
        and (Level=1  or Level=2 or Level=3 or Level = 4)
        and TimeCreated[
            @SystemTime&gt;='2016-11-27T15:11:00.000Z'
            and @SystemTime&lt;='2016-11-21T15:12:00.000Z'
        ]
    ]
]
  1. Linia query mówi, że wyszukiwania należy wykonywać w dowolnych node’ach najwyższego rzędu. Tak naprawdę chodzi o node
  2. Linia nakazuje przeszukać Tag . W ten sam sposób można się odnieść do sekcji
  3. Linia nakazuje przeszukać Tag , który znajduje się wewnątrz tagu
  4. Linia definiuje warunek, w którym przyrównujemy wartość atrybutu o nazwie ActivityID do określonego ciągu znaków
  5. Linia zamyka listę warunków sprawdzanych w obrębie tagu
  6. Linia definiuje warunek sprawdzający zawartość tagu nie posiadającego żadnych subtagów, tylko wartość.
  7. Linia i kolejne definiują warunek w obrębie tagu i odnoszą się do dwóch atrybutów tego tagu.

Wprowadzenie do Failover Cluster Generic Script Resource

Dzisiaj chciałbym poświęcić trochę miejsca bardzo słabo udokumentowanej funkcjonalności Klastra.
Skrypty zasobów generycznych (Generic Script Resource) umożliwiają uruchomić w środowisku klastrowym nawet bardzo skomplikowane z punktu widzenia startu i potrzebnych zasobów usługi, które nie mają wbudowanych mechanizmów zapewniających wysoką dostępność.
W systemie Windows Failover Cluster umożliwia tworzenie skryptów zarządzających stanem zasobów JEDYNIE w języku Visual Basic (VBScript).
Ponieważ jest to technologia archaiczna, to powstały różne skrypty dostępne w sieci, służące do wywoływania innych narzędzi skryptowych. Ja posłużę się wersją uruchamiającą skrypty Powershell, gdyż jest to najlepszy obecnie dostępny język skryptowy dla systemu Windows.
Jednak, zanim dojdziemy do przedstawienia właściwych rozwiązań, chciałbym omówić filozofię tworzenia takich skryptów.
W środowisku klastrowym każdy zasób ma swojego właściciela (Owner Host). Jest host, na którym w danym momencie uruchamiany jest kod odpowiadający za obsługę zasobu. Celowo piszę „kod odpowiadający za obsługę”, gdyż może być to trojaki typ kodu:

  1. Manager Usług
  2. Biblioteka DLL zarządzająca zasobem (na przykład maszyny wirtualne)
  3. Skrypt zasobu generycznego

Po prawdzie, to implementacja zarówno managera usług jak i zasobu skryptu generycznego jest wewnętrznie realizowana przez odpowiednią DLL, ale rozróżnienie to jest przydatne dla administratorów i wdrożeniowców mających zdecydować, w jaki sposób należy zapewnić wysoką dostępność.

Cykl życia zasobu można opisać pewnymi etapami, które są charakterystyczne dla każdego właściciela. Należą do nich:

  1. Inicjalizacja managera zasobu (Open)
  2. Uruchomienie zasobu (Online)
  3. „Obejrzenie stanu zasobu” (LooksAlive)
  4. Sprawdzenie stanu zasobu (IsAlive)
  5. Wyłączenie zasobu (Offline)
  6. Zniszczenie zasobu (Terminate)
  7. Zamknięcie managera zasobu (Close)

Nazwy funkcji Callback implementowane w skrypcie zasobu Podane zostały w nawiasach.
Istotne jest wyjaśnienie różnicy między LooksAlive a IsAlive, gdyż na pierwszy rzut oka wydaje się to być dość nietypowe rozwiązanie. Callback LooksAlive jest wywoływany często, żeby zmniejszyć możliwie najbardziej czas reakcji na ewentualną awarię. Czas wykonania tego callback’a jest ograniczony do 300ms.
Dopiero, gdy ta funkcja zwróci błąd wywoływana jest funkcja IsAlive.
Ponadto raz na około minutę wywoływana jest funkcja IsAlive niezależnie od opisanego powyżej mechanizmu. Wynika to z pryncypium szybkiego wykonania LooksAlive, a w konsekwencji pobieżnego sprawdzenia, które może coś (celowo, lub nie) przeoczyć.
Dlatego manager klastra i tak sprawdza pełną diagnostykę zasobu raz na minutę. Jest to na tyle nieduży czas, że jeszcze akceptowalny dla większości usług, a z drugiej strony jest on na tyle duży, że nie wprowadza znacznego obciążenia do systemu „władającego” usługą.
Pozostałe funkcje callback ze skryptu nie wymagają dłuższego omówienia.

Bardzo ważną sprawą do omówienia, gdyż z tym się mogą wiązać błędu i w konsekwencji problemy z uruchomieniem, jest kwestia zmiennych zasobu. Każdy zasób może (i powinien) przechowywać swój stan konfiguracji w przestrzeni klastra – dzięki temu unikniemy sytuacji, w której usługa będzie zachowywać się niespójnie na różnych hostach-właścicielach zasobu.
Istotnym jest, aby definiować zmienne zasobu na samym zasobie skryptu, a nie na grupie zasobów, czy też na zasobie adresu ip albo jakimkolwiek innym zasobie w grupie. Tylko zmienne zasobu skryptu (czyli zdefiniowane dla instancji typu Generic Script Resource) będą dostępne przez Api Klastra.

API klastra reprezentowane jest przez obiekt VBScript o nazwie

1
Resource

Przykład użycia tego obiektu prezentuje poniższa funkcja:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Function CheckProperties(ActionName, ErrorBaseCode)
    If Resource.PropertyExists("DebugVBA") = False Or Resource.PropertyExists("DebugPS") = False Then
        WshShell.LogEvent 1, "No Debugging Settings! Exiting."
        CheckProperties = ErrorBaseCode+1
        Exit Function
    End If
    LogEvent 4, "Enter " & ActionName & "()"
    If Resource.PropertyExists("PSScriptsPath") = False Then
        LogEvent 1, "Error " & ActionName & "(). No PSScriptsPath private property. Exiting."
        CheckProperties = ErrorBaseCode+2
        Exit Function
    End If
    If Resource.PropertyExists("QueueIndex") = False Then
        WshShell.LogEvent 1, ActionName & "(): No Cluster Queue Definition! Define QueueIndex private property. Exiting."
        CheckProperties = ErrorBaseCode+3
        Exit Function
    End If
    CheckProperties = 0
End Function

Windows Terminal Services Logon „Access Denied”

Dzisiaj przedstawię rozwiązanie problemu z Usługą Terminalową w środowisku z odrębnym serwerem Licencji Terminalowych.

Symptomy:

  • W trakcie logowania użytkownik otrzymuje komunikat „Access denied.”. Wyświetlany jest on zamiast ekranu logowania po uprzednim komunikacie „Welcome”.
  • W logu aplikacyjnym i systemowym nie występują żadne informacje o błędach, lub są one ewidentnie niezwiązane z podstawowym objawem.
  • W logu TerminalServices-LocalSessionManager występuje następujący wpis skorelowany z próbą logowania użytkownika: „Session X has been disconnected, reason code 12”, gdzie X oznacza numer sesji przydzielony konkretnej próbie logowania.
  • Problem ten dotyka zarówno systemy windows 2008 R2 jak i 2012 (R2).
  • Często towarzyszy tej sytuacji brak możliwości wymuszenia GPO

Tymczasowym rozwiązaniem problemu może być wykonanie dodatkowego wpisu w rejestrze:

1
2
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\
IgnoreRegUserConfigErrors (DWORD) = 1

Po dodaniu tego wpisu konieczne jest ponowne uruchomienie komputera.

Po zażegnaniu kryzysu związanego z brakiem możliwości pracy użytkowników na spokojnie można przystąpić do diagnostyki, co się zepsuło tak naprawdę.
W tym konkretnym przypadku przyczyną był błędnie skonfigurowany Firewall na kontrolerach domeny przy użyciu GPO, gdzie był zabroniony ruch „SMB over TCP”.
Przyczyn należy w każdym razie szukać w otoczeniu kontrolerów domeny.

Failover Cluster Generic Script Resource Failed 0x80070009

Witajcie,

Dzisiaj chciałbym się podzielić spostrzeżeniem mocno nieintuicyjnego zachowania funkcjonalności Failover Clustering w Windows 2012 R2.
Mianowicie, może się zdarzyć, że po przygotowaniu skryptu kontrolującego zachowanie aplikacji (Generic Script), której chcemy zapewnić wysoką dostępność i po konfiguracji zgodnie z tym blogiem Zespołu produktowego Microsoft zasób klastra nie zostanie uruchomiony, a status zasobu będzie zawierał informację

1
The storage control block is invalid.

Przedstawia to poniższy zrzut ekranowy:
Status zasobu klastrowego
Kiedy zgodnie z sugestią z komunikatu o błędzie wyświetlimy rozszerzoną informację o błędzie uzyskamy informację o kodzie błędu

1
0x80070009

Rozszerzona informacja o błędzie
Podobny wpis zostanie odłożony w logu systemowym klastra:
Log systemowy klastra

W takiej sytuacji należy przede wszystkim się upewnić, że przygotowany przez nas skrypt nie zwraca z żadnego wywołania API wartości 0x9.
Gdy posiadamy taką pewność, to błąd ten oznacza, że skrypt Visual Basic ma niepoprawną składnię i menedżer zasobów klastra nie był w stanie prawidłowo go skompilować.
Dlatego dobrą praktyką jest przed utworzeniem zasobu klastrowego weryfikacja poprawności kompilacji skryptu. W tym celu należy wydać polecenie z linii poleceń:

1
cscript.exe C:\pełna\ścieżka\do\pliku.vbs

Ponieważ skrypt zawierać powinien same definicje funkcji, a nie ma żadnych ich wywołań (cecha charakterystyczna wywołań zwrotnych – „CallBack”), to prawidłowo napisany skrypt nie powinien nic wykonać ani wyświetlić.
W przypadku nieprawidłowej walidacji wynik będzie podobny do poniższego zrzutu ekranu:
Błąd walidacji skryptu

Pozdrawiam serdecznie i życzę samych poprawnych skryptów!

Migracja zasobów między subskrypcjami w MS Azure

W chmurze Microsoft Azure użytkownik może posiadać dowolną liczbę subskrypcji. Subskrypcja jest najmniejszą jednostką konfigurującą sposób płatności i zakres własności zasobów.
Każda subskrypcja generuje swój osobny Billing. Nie ma żadnego znaczenia w tym przypadku fakt, że jeden użytkownik, czy organizacja jest właścicielem subskrypcji. Jedna subskrypcja, jeden rachunek. Istnieje wyjątek w postaci umów typu Enterprise, gdzie ten model jest bardziej skomplikowany, ale ten temat zostawiamy na boku.
Istotne jest to, że będąc indywidualnym właścicielem kilku subskrypcji, można dostać na przykład 3 rachunki opiewające na 2 euro. To potrafi być irytujące.
Dlatego zaistniała potrzeba połączenia subskrypcji ze sobą.
Jedną metodą, jaka jest dostępna w Azure, na wykonanie takiej akcji jest migracja zasobów do jednej z subskrypcji i odwołanie pozostałych. W sieci można znaleźć dużo pytań na ten temat, jednak mało która odpowiedź jest konkretna. Okazuje się jednak, że rozwiązanie jest bardzo proste i wspierane. Opisane dokładnie w szczegółach jest w tym artykule.
Tutaj tylko przytoczę informację o tym, że możliwość migracji jest uzależniona od konkretnego typu zasobu i niektóre zasoby posiadają pewne ograniczenia w przenoszeniu.
Pełna lista zasobów wspierających przenoszenie dostępna jest tutaj.

Generowanie Żądania certyfikatu z openssl dla Microsoft Enterprise CA

Dawno temu pisałem o tym, jak wygenerować żądanie certyfikatu dla systemów nie będących Windowsami tak, aby dało się certyfikat wystawić na Microsoft Enterprise CA. Jako przykład podałem generowanie certyfikatów serwera vCenter
Niedawno temat powrócił, ale w nowej odsłonie, gdyż serwer vSphere wymaga zdefiniowania w certyfikacie odpowiednich Nazw Alternatywnych. Powstało pytanie, jak pogodzić te dwie funkcjonalności.
Okazuje się to być całkiem proste, trzeba tylko pamiętać, że choć plik konfiguracji openssl pozwala na wiele sekcji opisujących rozszerzenia żądania certyfikatu, to tylko jedna z nich może być wykorzystywana w trakcie generowania certyfikatu. Dlatego przygotowując plik konfiguracyjny dla określonego serwera warto uporządkować jego strukturę, względem propozycji przedstawionej w poprzednim wpisie.
Przykładowy plik konfiguracyjny może wyglądać następująco:

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
openssl_conf = openssl_init

[ openssl_init ]
oid_section = new_oids

[ req ]
default_bits = 2048
default_keyfile = rui.key
distinguished_name = req_distinguished_name
encrypt_key = no
prompt = no
string_mask = nombstr
req_extensions = v3_req

[ new_oids ]
MsCaCertificateTemplate = 1.3.6.1.4.1.311.20.2

[ v3_req ]
basicContraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = DNS:server01, DNS:server01.domena.test
MsCaCertificateTemplate = ASN1:PRINTABLESTRING:VMwareCertificate

[ req_distinguished_name ]
countrName = PL
stateOrProvinceName = Malopolskie
localityName = Krakow
0.organizationName = Firma
organizationalUnitName = Oddzial
commonName = server01.domena.test

Analizując najważniejsze części:

  • Linia 1. Wskazuje na sekcję będącą konfiguracją globalną.
  • Linia 4. Wskazuje na sekcję defniującą OIDy. Linia ta jest jedyną w sekcji konfiguracji globalnej
  • Linia 13. Wskazuje na sekcję definiującą rozszerzenia, które zostaną dodane do żądania certyfikatu
  • Linia 15. Definiuje sekcję z OIDami.
  • Linia 16. Definiuje OID zarejestrowany i użytkowany przez Microsoft do oznaczania rozszerzenia definiującego szablon certyfikatu
  • Linia 22. Definiuje alternatywne nazwy serwera. Należy zwrócić uwagę na fakt, że w przykładzie używany jest prefiks DNS: Możliwe są także inne prefiksy.
  • Linia 23. Definiuje nazwę używanego szablonu certyfikatów. Należy zwrócić uwagę, że wykorzystywany jest wariant nazwy bez żadnych spacji. Nazywa się on „Certificate Template Name”, w przeciwieństwie do nazwy przyjaznej, nazywającej się „Certificate Template Display Name”

Pozostała cześć jest standardowa dla każdego żądania obsługiwanego przez openssl.