Strona główna
Projekt
Harmonogram
Przebieg pracy
Raporty
Referaty
Dokumentacja
Linki


PKI
Kryptografia
SSL
Instalacja
mod_ssl
IMAP
Słownik




  wersja drukowalna

Instrukcja konfiguracji serwera Apache
z użyciem certyfikatów PKI UMK

Adam Laskowski
22-04-2001

0. Wstęp

Dokument ten opisuje proces konfiguracji uprawnień dostępu do serwera Apache w oparciu o certyfikaty SSL. Nie zawiera on instrukcji instalacji Apache z mod_ssl - zawarta jest ona w odrębnym dokumencie.

W treści dokumentu wszystkie ścieżki podane są (o ile nie jest to wyraźnie określone) relatywnie względem katalogu głównego Apache'a - typowo /usr/local/apache.

1. Instalacja certyfikatów serwera

Zakładamy, że przy instalacji Apache nie zostały wygenerowane certyfikaty serwera. Jeżeli tak się stało to należy te certyfikaty skasować, aby nie wprowadzać zbędnego zamieszania w katalogach konfiguracyjnych Apache.

1.1. Lokalizacja certyfikatów

Wszystkie pliki certyfikatów, kluczy prywatnych, CRL itp. są przechowywane w podkatalogach katalogu conf:

  • ssl.crt/ - certyfikat serwera, certyfikaty CA
  • ssl.key/ - klucze prywatne certyfikatów
  • ssl.csr/ - zlecenia certyfikacji (Certificate Signing Request)
  • ssl.crl/ - listy certyfikatów odwołanych (Certificate Revocation List)
  • ssl.prm/ - parametry kluczy DSA (DSA Parameter Files)

Trzy ostatnie rodzaje plików nie są używane w ramach naszej PKI - będziemy się zajmować tylko plikami .crt oraz .key.


1.2. Rozpakowanie certyfikatów

Urząd Certyfikacyjny dostarcza nam certyfikat w formie zaszyfrowanego i spakowanego pliku .p12. Należy więc taki plik rozpakować w bezpiecznym miejscu używając polecenia openssl pkcs12:

  # openssl pkcs12 -nocerts \
                   -in server.p12 -out server.key
  Enter Import Password: *******
  MAC verified OK
  Enter PEM pass phrase: *******
  Veifying password - Enter PEM pass phrase: *******
  # openssl pkcs12 -clcerts -nokeys \
                   -in server.p12 -out server.crt
  Enter Import Password: *******
  MAC verified OK
  # openssl pkcs12 -cacerts -nokeys \
                   -in server.p12 -out chain.crt
  Enter Import Password: *******
  MAC verified OK
  # 

Hasła, które podajemy przy rozpakowywaniu to odpowiednio:

  • Import password - hasło zabezpieczające plik .p12
  • PEM pass phrase - hasło zabezpieczające klucz prywatny

Hasło klucza prywatnego

Musimy w tym miejscu podjąć ważną decyzję: czy klucz prywatny naszego serwera będzie zabezpieczony hasłem. W zależności od okoliczności możemy:

  • Zabezpieczyć klucz: zwiększamy wtedy bezpieczeństwo serwera, jednak przy każdym jego restarcie musimy ręcznie wpisać hasło klucza prywatnego. Utrudnia to automatyzację serwera i zmniejsza odporność na awarie.
  • Nie zabezpieczać klucza: serwer wtedy potrafi podnieść się automatycznie np. po restarcie, jednak narażamy się na ryzyko dostania się klucza w niepowołane ręce.

Jeżeli zdecydujemy się używać klucza prywatnego serwera w postaci nie zabezpieczonej hasłem, to w pierwszym poleceniu (eksportującym klucz prywatny) musimy dodać parametr -nodes. Program openssl nie będzie wtedy pytał o PEM pass phrase:

  # openssl pkcs12 -nocerts -nodes \
                   -in server.p12 -out server.key
  Enter Import Password: *******
  MAC verified OK
  # 


Otrzymaliśmy zatem trzy pliki:

  • server.crt - certyfikat serwera
  • server.key - klucz prywatny serwera
  • chain.crt - łańcuch certyfikatów potwierdzających certyfikat serwera

Certyfikaty (*.crt) kopiujemy do katalogu conf/ssl.crt, a klucz publiczny (server.key) do katalogu conf/ssl.key.

1.3. Konfiguracja serwera

Zanim skonfigurujemy pliki certyfikatów należy poprawić konfigurację portów Apache. Domyślna konfiguracja bowiem zakłada, że serwer HTTP działa na porcie 8080, a HTTPS - na porcie 8433. Należy to poprawić, ustawiając odpowiednio port 80 i 443 w następujących miejscach:

Domyślny serwer (HTTP) używa dyrektywy Port w głównym wątku pliku konfiguracyjnego. Port SSL natomiast ustawiamy w sekcji otoczonej nagłówkiem <IfDefine SSL>. Należy jeszcze poprawić nagłówek domyślnego VirtualHost'a- znajdujemy linię:

<VirtualHost _default_:8443>

i zmieniamy numer portu na 443.



Aby skonfigurować Apache tak, aby używał właśnie skopiowanych certyfikatów do autoryzacji serwera i bezpiecznych połączeń należy poinformować go o lokalizacji i nazwach plików. W tym celu wyszukujemy i poprawiamy następujące pola w pliku conf/httpd.conf:

  • SSLCertificateFile
    wpisujemy tu pełną ścieżkę do pliku server.crt
  • SSLCertificateKeyFile
    wpisujemy tu pełną ścieżkę do pliku server.key
  • SSLCertificateChainFile
    wpisujemy tu pełną ścieżkę do pliku chain.crt
  • SSLCACertificateFile
    wpisujemy tu pełną ścieżkę do pliku chain.crt

Jeżeli chcemy autoryzować dostęp klientów włączonych w struktury certyfikacji inne niż ta, do której należy serwer WWW, to możemy, korzystając z dyrektywy SSLCACertificateFile podać lokalizację pliku z certyfikatami innych urzędów certyfikacyjnych. Można tam wskazać np. plik conf/ssl.crt/ca-bundle.crt - przy instalacji Apache ładowany tam jest zbiór certyfikatów największych światowych urzędów certyfikacyjnych.

Podane opcje konfiguracyjne możemy definiować osobno w obrębie każdego wirtualnego hosta udostępnianego przez dany serwer.

1.4. Uruchamianie serwera

Apache z obsługą mod_ssl uruchamiamy w standardowy sposób - przy użyciu polecenia bin/apachectl. Mamy następujące możliwości:

  • bin/apachectl start
    Uruchomienie wyłącznie standardowego serwera HTTP
  • bin/apachectl startssl
    Uruchomienie serwera HTTP i HTTPS
  • bin/apachectl stop
    Zatrzymanie serwera
  • bin/apachectl restart
    Przeładowanie konfiguracji serwera (lub uruchomienie, jeśli nie działa)

Zatem uruchamiamy serwer HTTPS:

  # bin/apachectl startssl
  Apache/1.3.14 mod_ssl/2.7.1 (Pass Phrase Dialog)
  Some of your private key files are encrypted 
  To read them you have to provide us with the pass phrases.

  Server www.ds3.uni.torun.pl:443 (RSA)
  Enter pass phrase:

  Ok: Pass Phrase Dialog successful.
  bin/apachectl startssl: httpd started
  # 

Jak widać, klucz prywatny jest zaszyfrowany i przy starcie serwera należało podać jego hasło.

2. Konfigurowanie uprawnień do zasobów serwera

Konfiguracja dostępu do zasobów bazuje całkowicie na jednoznacznej nazwie obiektu (Distinguished Name, DN), zawartej w certyfikacie. Certyfikat kliencki osoby próbującej uzyskać dostęp powinien (choć nie jest to regułą) być umieszczony w tej samej strukturze PKI, co serwer WWW. Jak już wiemy, serwer przechowuje certyfikaty wszystkich urzędów certyfikacyjnych aż do root CA zatem może zawsze sprawdzić autentyczność certyfikatu klienta.

Zakładamy, że Czytelnik jest zaznajomiony z ogólnymi regułami konfigurowania dostępu do stron w Apache (bez użycia SSL). Jeżeli pojęcia zasięgu (scope), lokacji (location), czy wirtualnego serwera (virtual host) nie są Czytelnikowi znane, to odsyłamy do dokumentacji Apache.

Przypomnijmy, że dostęp do zasobów można konfigurować globalnie (w pliku httpd.conf) lub lokalnie (z użyciem plików .htaccess). Pliki .htaccess działają podobnie jak odpowiadające im sekcje <Directory> w pliku konfiguracyjnym, ale umożliwiają np. definiowanie uprawnień przez właściciela strony.

W dalszym ciągu opiszemy opcje mod_ssl umożliwiające dokładne konfigurowanie uprawnień dostępu bez rozdrabniania się na scope w jakim wystepują - znaczenie jest w większości przypadków identyczne.

2.1. SSLRequireSSL

Włączenie tej opcji powoduje, że fragment danych, do którego uprawnienia właśnie definiujemy będzie dostępny jedynie przy użyciu protokołu https. Jeżeli klient będzie próbował dostać się do niego przy użyciu połączenia nieszyfrowanego, to otrzyma błąd Permission Denied.

2.2. SSLVerifyClient poziom

Opcja ta ustala dopuszczalny sposób weryfikacji klienta chcącego uzyskać dostęp do danego zasobu. Możliwe wartości parametru poziom to:

  • none - certyfikat nie jest wymagany
  • optional - certyfikat nie jest wymagany, lecz może zostać przedstawiony jeżeli przeglądarka wyrazi taką chęć
  • optional_no_ca - certyfikat jest wymagany, jednak nie musi on koniecznie być potwierdzony przez zaufane CA
  • require - certyfikat jest wymagany i musi on mieć potwierdzenie możliwe do sprawdzenia przy użyciu certyfikatów CA istniejących w bazie serwera.

W praktyce używamy jedynie opcji none lub require.

2.3. SSLVerifyDepth poziom

Ta opcja umożliwia ustalenie ilości poziomów weryfikacji CA dla certyfikatu klienta. Inaczej: ilośći certyfikatów nadrzędnych CA uwzględnionych przy sprawdzaniu autentyczności certyfikatu klienta dla włączonej opcji SSLVerifyClient require.

W praktyce opcja ta ma niewielkie znaczenie, warto ją ustawić na względnie dużą liczbę, w okolicach 10.

2.4. SSLRequire wyrażenie_logiczne

Jest to najbardziej rozbudowana opcja mod_ssl. W skrócie działa ona tak, że jeżeli wyrażenie logiczne ma wartość true, to klient uzyska dostęp do zasobów, jeżeli zaś false, to otrzyma komunikat o braku dostępu.

Warunki mogą być bardzo rozbudowane - możemy używać w nich standardowej składni shella bash, z pewnymi ograniczeniami opisanymi szczegółowo w dokumentacji mod_ssl. Oto opis składni warunku logicznego mod_ssl:

wyrażenie ::= "true" | "false"
            | "!" wyrażenie
            | wyrażenie "&&" wyrażenie
            | wyrażenie "||" wyrażenie
            | "(" wyrażenie ")"
            | składnik

składnik  ::= słowo "==" słowo | słowo "eq" słowo
            | słowo "!=" słowo | słowo "ne" słowo
            | słowo "<"  słowo | słowo "lt" słowo
            | słowo "<=" słowo | słowo "le" słowo 
            | słowo ">"  słowo | słowo "gt" slowo
            | słowo ">=" słowo | słowo "ge" słowo
            | słowo "in" "{" lista "}"
            | słowo "=~" wyrażenie_regularne
            | słowo "!~" wyrażenie_regularne

lista     ::= słowo
            | lista "," słowo

słowo     ::= cyfra
            | łańcuch
            | zmienna
            | funkcja
 
cyfra     ::= [0-9]+
łańcuch   ::= "..."
zmienna   ::= "%{"nazwa_zmiennej"}"
funkcja   ::= nazwa_funkcji "(" argumenty ")"

Jak na razie jedyna dostępna funkcja to file(nazwa_pliku), której wynikiem jest zawartość podanego pliku. Można ją np. porównać z wynikiem ewaluacji wyrażenia regularnego. Dostępnych zmiennych natomiast jest mnóstwo - większość z nich dotyczy konkretnych pól z certyfikatu klienta lub serwera:

Standardowe zmienne Apache i CGI:

HTTP_USER_AGENT        PATH_INFO             AUTH_TYPE
HTTP_REFERER           QUERY_STRING          SERVER_SOFTWARE
HTTP_COOKIE            REMOTE_HOST           API_VERSION
HTTP_FORWARDED         REMOTE_IDENT          TIME_YEAR
HTTP_HOST              IS_SUBREQ             TIME_MON
HTTP_PROXY_CONNECTION  DOCUMENT_ROOT         TIME_DAY
HTTP_ACCEPT            SERVER_ADMIN          TIME_HOUR
HTTP:nagłówek          SERVER_NAME           TIME_MIN
THE_REQUEST            SERVER_PORT           TIME_SEC
REQUEST_METHOD         SERVER_PROTOCOL       TIME_WDAY
REQUEST_SCHEME         REMOTE_ADDR           TIME
REQUEST_URI            REMOTE_USER           ENV:zmienna
REQUEST_FILENAME

Dodatkowe zmienne związane z SSL:

HTTPS                  SSL_CLIENT_M_VERSION   SSL_SERVER_M_VERSION
                       SSL_CLIENT_M_SERIAL    SSL_SERVER_M_SERIAL
SSL_PROTOCOL           SSL_CLIENT_V_START     SSL_SERVER_V_START
SSL_SESSION_ID         SSL_CLIENT_V_END       SSL_SERVER_V_END
SSL_CIPHER             SSL_CLIENT_S_DN        SSL_SERVER_S_DN
SSL_CIPHER_EXPORT      SSL_CLIENT_S_DN_C      SSL_SERVER_S_DN_C
SSL_CIPHER_ALGKEYSIZE  SSL_CLIENT_S_DN_ST     SSL_SERVER_S_DN_ST
SSL_CIPHER_USEKEYSIZE  SSL_CLIENT_S_DN_L      SSL_SERVER_S_DN_L
SSL_VERSION_LIBRARY    SSL_CLIENT_S_DN_O      SSL_SERVER_S_DN_O
SSL_VERSION_INTERFACE  SSL_CLIENT_S_DN_OU     SSL_SERVER_S_DN_OU
                       SSL_CLIENT_S_DN_CN     SSL_SERVER_S_DN_CN
                       SSL_CLIENT_S_DN_T      SSL_SERVER_S_DN_T
                       SSL_CLIENT_S_DN_I      SSL_SERVER_S_DN_I
                       SSL_CLIENT_S_DN_G      SSL_SERVER_S_DN_G
                       SSL_CLIENT_S_DN_S      SSL_SERVER_S_DN_S
                       SSL_CLIENT_S_DN_D      SSL_SERVER_S_DN_D
                       SSL_CLIENT_S_DN_UID    SSL_SERVER_S_DN_UID
                       SSL_CLIENT_S_DN_Email  SSL_SERVER_S_DN_Email
                       SSL_CLIENT_I_DN        SSL_SERVER_I_DN
                       SSL_CLIENT_I_DN_C      SSL_SERVER_I_DN_C
                       SSL_CLIENT_I_DN_ST     SSL_SERVER_I_DN_ST
                       SSL_CLIENT_I_DN_L      SSL_SERVER_I_DN_L
                       SSL_CLIENT_I_DN_O      SSL_SERVER_I_DN_O
                       SSL_CLIENT_I_DN_OU     SSL_SERVER_I_DN_OU
                       SSL_CLIENT_I_DN_CN     SSL_SERVER_I_DN_CN
                       SSL_CLIENT_I_DN_T      SSL_SERVER_I_DN_T
                       SSL_CLIENT_I_DN_I      SSL_SERVER_I_DN_I
                       SSL_CLIENT_I_DN_G      SSL_SERVER_I_DN_G
                       SSL_CLIENT_I_DN_S      SSL_SERVER_I_DN_S
                       SSL_CLIENT_I_DN_D      SSL_SERVER_I_DN_D
                       SSL_CLIENT_I_DN_UID    SSL_SERVER_I_DN_UID
                       SSL_CLIENT_I_DN_Email  SSL_SERVER_I_DN_Email
                       SSL_CLIENT_A_SIG       SSL_SERVER_A_SIG
                       SSL_CLIENT_A_KEY       SSL_SERVER_A_KEY
                       SSL_CLIENT_CERT        SSL_SERVER_CERT
                       SSL_CLIENT_CERT_CHAINn
                       SSL_CLIENT_VERIFY

Nie opisujemy tutaj znaczenia tych zmiennych, gdyż w większości przypadków jest ono albo oczywiste, albo pokrywa się ze znaczeniem analogicznej zmiennej środowiskowej, lub nagłówka HTTP.

3. Przykłady

Dostęp tylko dla ściśle określonych użytkowników wyłącznie przez SSL:

  SSLRequireSSL
  SSLVerifyClient      require
  SSLVerifyDepth       5
  SSLRequire \
    (%{SSL_CLIENT_S_DN_CN} in { "muflon" "perkins" }) \
    and (%{SSL_CLIENT_S_DN_OU} == "WMiI") \
    and (%{SSL_CLIENT_S_DN_OU} == "UMK") \
    and (%{SSL_CLIENT_S_DN_O} == "MEN")

Dostęp tylko dla pracowników WMiI:

  SSLRequireSSL
  SSLVerifyClient      require
  SSLVerifyDepth       5
  SSLRequire \
    (%{SSL_CLIENT_S_DN_OU} == "staff") \
    and (%{SSL_CLIENT_S_DN_OU} == "WMiI") \
    and (%{SSL_CLIENT_S_DN_OU} == "UMK") \
    and (%{SSL_CLIENT_S_DN_O} == "MEN")

Bardziej skomplikwoany przykład: dostęp tylko dla studentów w dniach roboczych od godziny 8 do 20, z użyciem dwóch wyróżnionych protokołów szyfrowania. Dodatkowo zdefiniowano "furtkę" pozwalającą na dostęp z podsieci 158.75.2.* bez powyższych ograniczeń (ale wyłącznie dla osób legitymujących się ważnym certyfikatem):

  SSLRequireSSL
  SSLVerifyClient      require
  SSLVerifyDepth       5
  SSLRequire \
   ((%{SSL_CIPHER} !~ m/^(EXP|NULL)-/) \
    and (%{SSL_CLIENT_S_DN_OU} == "WMiI") \
    and (%{SSL_CLIENT_S_DN_OU} == "UMK") \
    and (%{SSL_CLIENT_S_DN_O} eq "MEN") \
    and (%{SSL_CLIENT_S_DN_OU} in {"studinfo" "studmat"}) \
    and (%{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5) \
    and (%{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20) \
   ) or (%{REMOTE_ADDR} =~ m/^158\.75\.2\.[0-9]+$/)