Konfiguracja PKI dla strongswan
Errata 22.05.2026r. - Kilka mniejszych poprawek + korekta dotycząca nazwy przedstawionej tu konfiguracji, to jest konfiguracja typu “jumphost”, a nie jak została tu wcześniej błędnie przytoczona jako “Road Warrior”. Podziękowania dla recenzenta Piotra :)
Wpis o tym jak skonfigurować bardzo podstawowe PKI (public key infrastrucutre) dla Strongswan IPSec. Nie jest do dogłębna analiza anie rozłożenia na czynniki pierwsze, a jedynie podręczny tutorial na przyszłość, żebym znów nie musiał poświęcać więcej niż 5 minut na zadanie, które jest w zasadzie trywialne… Natomiast może być to ewentualnie punkt zaczepienia do PKI jako takiego.
Na początek należy pamiętać, że Strongswan wymaga, aby w PKI identyfikatory zawierały się w polach SAN (subject alternative name[s]) lub DN (Distinguished Name). Bez tego, przy próbach nawiązania połączenia przez service charon-systemd (za pośrednictwem swanctl) będą prawdopodobnie widoczne takie oto błędy:
(...) charon-systemd (...) no trusted rsa public key found for "example.com"
Gdzie example.com to identyfikator hosta próbującego nawiązać
połączenie. W komunikacie błędu mogą być też widoczne nazwy innych
algorytmów szyfrujących, w zależności od tego co zostało użyte przy
generowaniu certyfikatów. A w takim razie jak przygotować działający
zestaw certyfikatów dla wybranej konfiguracji połączenia?
Przypadek “jumphost”
Wybrana przeze mnie konfiguracja to tzw. “jumphost”. Konfigurację
oparłem na wariancie typu “Road
Warrior”
opisanym w dokumentacji Strongswan. Natomiast moją intencją było aby
pomiędzy dwoma hostami, jednym widocznym publicznie (Peregrin),
drugim będącym routerem dla pewnej podsieci przebywającym za NATem
(Meriadoc), nawiązywane zostało połączenie szyfrowane (za pomocą
IPSec), po czym aby każdy z hostów z grupy w podsieci mógł z tego szyfrowanego połączenia
swobodnie (albo w sposób kontrolowany) korzystać. W rezultacie umożliwia to aby dowolne hosty znajdujące się za NATem były dostępne z poziomu Internetu. Zamierzona
kofiguracja została zobrazowana poniżej.

Zatem potrzebuje łącznie dwóch “entity” certyfikatów dla każdego z
hostów biorących udział w połączeniu IPSec, to jest dla Meriadoca i
Peregrina. Ponieważ uznaniowo stwierdziłem, że jestem w stanie
samodzielnie zapewnić bezpieczeństwo swoich danych, to dodatkowo
wygeneruję tzw. root certificate (self signed), którym te “entity”
certyfikaty podpiszę. Innymi słowy, sam dla siebie zostanę CA
(Certificate Authority).
Generowanie Root Certificate - CA
Bazuję tutaj na tutorialu generowania certyfikatów znalezionych na
tej
stronie. Natomiast w internecie można znaleźć wiele takich
tutoriali. W moim przypadku korzystam z dostępnego pod Linuxem
narzędzia openssl. Natomiast warto wziąć
pod uwagę, że Strongswan również dołączył do swojego zestawu narzędzie
dedykowane właśnie do generowania odpowiednich certyfikatów,
pki.
openssl req -newkey rsa:4096 \
-x509 \
-sha256 \
-days 3650 \
-nodes \
-out CA.pem \
-keyout CA.key
Z powyższej komendy uzyskuję root certyfikat CA.pem wraz z jego
kluczem prywatnym CA.key[1].
Generowanie entity certificates
Następnie przystępują do generowania “entity” certyfikatów - tylu ile
potrzebuję, czyli w moim przypadku dwóch. Tutaj bazuję na tutorialu z
tej
strony. Nazwy “entities” jakie tutaj wykorzystam to Meriadoc i
Peregrin - posłużą one też później jako identyfikatory dla
Strongswan.
W pierwszej kolejności przygotowuję plik konfiguracyjny zawierający
informacje o każdym z “entities”. Na przykład, dla “entity” Meriadoc
będzie to:
# ./meriadoc.conf
[ req ]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = v3_req
[ dn ]
C = PL
ST = Mazowieckie
L = Warszawa
O = Durins Gate Company
CN = Meriadoc
[ v3_req ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = meriadoc
DNS.2 = meriadoc.durinsgate.com
IP.1 = 10.1.0.1
Nie będę tutaj omawiał szczegółowo każdego z pól pliku
konfiguracyjnego, natomiast zwracam szczególną uwagę na ostatnią
strukturę alt_names, czyli “SAN”. Jak wspomniałem na samym początku,
są one niezbędne dla strongswan (wystarczy jedno).
Następnie wygeneruję klucz prywatny dla certyfikatu dla
Meriadoca.
openssl genrsa -out meriadoc_key.pem 4096
Po czym przygotuję tzw. CSR, czyli certificate signing request. Bazuje
on na informacjach zawartych już w pliku konfiguracyjnym przygotowanym
dla Meriadoca.
openssl req -new -key meriadoc_key.pem -out meriadoc.csr -config meriadoc.conf
I wreszcie podpiszę, jako CA, CSR dla Meriadoca przy użyciu mojego zestawu root certificate i root private key.
openssl x509 -req -in meriadoc.csr -CA CA.pem -CAkey CA.key -out meriadoc.crt -days 365 -sha256 -extfile meriadoc.cnf -extensions v3_req
To samo powtarzam dla entity Peregrin odpowiednio wypełniając jego
plik konfiguracyjny.
Konfiguracja Strongswan
Na odpowiednie hosty przesyłam odpowiednie certyfikaty w miejsca,
gdzie charon-systemd się ich spodziewa, czyli do właściwych
podkatalogów w katalogu /etc/swanctl (jest to katalog wykorzystywany
pod Debianem i Fedorą; dla innych dystrybucji czy systemów
operacyjnych może być to inny katalog, należy na to zwrócić
uwagę). Powinno to wyglądać tak:
meriadoc$ tree /etc/swanctl/
/etc/swanctl/
├── conf.d
├── ecdsa
├── pkcs12
├── pkcs8
├── private
│ └── meriadoc_key.pem
├── pubkey
├── rsa
├── swanctl.conf
├── x509
│ └── meriadoc.pem
├── x509aa
├── x509ac
├── x509ca
│ └── CA.pem
├── x509crl
└── x509ocsp
Na danym hoście, do którego należy dany certyfikat, powinny znaleźć
się publiczna część certyfikatu tego entity (meriadoc.pem), prywata
część certyfikatu (meriadoc_key.pem) oraz publiczna część
certyfikatu CA, którym dany “entity” certyfikat został podpisany (CA.pem). Dla
Peregrina analogicznie.
Konfiguracja swanctl.conf - przypadek “jumphost”
Do ukończenia konfiguracji niezbędne jest jeszcze przygotowanie plików
konfiguracyjnych swanctl.conf. Zakładam tutaj, że “entity”
Meriadoc jest niepublicznie dostępne i skrywa za sobą subnet innych
hostów, natomiast “entity” Peregrin stanowi publiczny gateway, to
jest jumphost, dla Meriadoca i jego podsieci, czyli jest widoczny w
Internecie.
Meriadoc swanctl.conf - strona prywatna
Ta strona będzie odpowiedzialna za nawiązanie połączenia IPSec, ponieważ tylko ona może w sposób bezpośredni nawiązać połączenie z drugą stroną. Konfiguracja dla tej strony może wyglądać następująco:
connections {
home {
remote_addrs = peregrin.durinsgate.com
local {
auth = pubkey
certs = meriadoc.pem
id = meriadoc
}
remote {
auth = pubkey
id = peregrin
}
children {
home {
start_action = start
local_ts = 10.1.0.0/16
}
}
}
}
Po szczegóły można przejść do dokumentacji Strongswan.
Peregrin swanctl.conf - strona publiczna
Ta strona ma za zadanie odebrać nawiązywane przez stronę prywatną połączenie i zweryfikować czy może ono zostać ustanowione. Konfiguracja może wyglądać następująco:
connections {
jh {
local {
auth = pubkey
certs = peregrin.pem
id = peregrin
}
remote {
auth = pubkey
}
children {
meriadoc-net {
remote_ts = 10.1.0.0/16
}
}
}
}
Sprawdzenie statusu połączenia
Na koniec, pokrótce weryfikacja czy konfiguracja PKI/swanctl
przebiegła pomyślnie. Ze strony prywatnej, tj. Meriadoc, można
ręcznie nawiązać połączenie z pomocą komendy swanctl -i -i home,
natomiast w pierwszej kolejności powinny zostać przez swanctl
załadowane nowa konfiguracja i klucze. Żeby to zapewnić, można
zrestartować service strongswan, natomiast to też spowoduje
automatyczną próbę nawiązania połączenia.
# systemctl restart strongswan
W celu weryfikacji czy połączenie zostało zestawione, to znaczy czy
tzw. SA (security assosiation) zostało utworzone, można wykorzystać
komendę swanctl -l. Wynik powinien być podobny jak ten przedstawiony
poniżej.
# swanctl -l
jh: #1, ESTABLISHED, IKEv2, (...)
local 'peregrin' @ <Peregrin public ip address>[4500]
remote 'meriadoc' @ <Meriadoc NAT ip address>[<random port>]
(...)
established 5789s ago, rekeying in 8491s
meriadoc-net: #1, (...)
installed 2546s ago, rekeying in 863s, expires in 1414s
in c4d35ddc, 85100 bytes, 817 packets, 9s ago
out c7e44988, 75400 bytes, 910 packets, 9s ago
local <Peregrin public ip address>/32
remote 10.1.0.0/16
Klucz prywatny - jak nazwa wskazuje - należy zachować w prywatności, w przeciwieństwie do klucza publicznego, który będzie widoczny dla każdego. W przypadku klucza prywatnego root certificate sprawa jest dodatkowo na tyle poważna, że utrata prywatności tego klucza powoduje zupełną utratę bezpieczeństwa całego PKI opartego na takim root certificate. “Keep it secret, keep it safe”. ↩︎

