ubuntuusers.de

Bash vHost SSL Path auslesen

Status: Gelöst | Ubuntu-Version: Server 16.04 (Xenial Xerus)
Antworten |

beLi3VeR

Avatar von beLi3VeR

Anmeldungsdatum:
22. April 2006

Beiträge: 387

Servus,

habe mal wieder ein etwas knifflige Aufgabe und ich hoffe ihr könnt mir helfen. Ich will ein Script basteln, dass auf einer vHost Datei mit die SSL Cert Pfade ausließt, also diese Infos:

1
2
3
    SSLCertificateFile /etc/ssl/certs/dddd
    SSLCertificateKeyFile /etc/ssl/private/dddd
    SSLCertificateChainFile /etc/ssl/certs/ddd

Soweit so gut. Wäre ja zu einfach:

1
2
3
SSLCertificateFile=$(grep -n "SSLCertificateFile" /path/to/vhost.conf | awk '{print $3}')
SSLCertificateKeyFile=$(grep -n "SSLCertificateKeyFile" /path/to/vhost.conf | awk '{print $3}')
SSLCertificateChainFile=$(grep -n "SSLCertificateChainFile" /path/to/vhost.conf | awk '{print $3}')

Problem, in dieser vHost Datei sind viele vHosts abgelegt:

  • example.de

  • sub.example.de

  • sub2.example.de

Jetzt will ich aber nur von example.de die Informationen haben. Habe ihr hier einen Tipp wie ich das am besten hinbekomme? Die Domains stehen auch nur in der ServerName Variable von Apache.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13213

Zunächst einmal brauchst Du nicht grep und awk. In diesem Fall wird vermutlich awk das Werkzeug der Wahl sein. Wenn diese Beispiele das korrekte Format enthalten, dann kann man das ggf. so machen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ cat vhost.conf 
<VirtualHost 172.20.30.40:80>
ServerName sub2.example.com
DocumentRoot /www/domain-80
    SSLCertificateFile /etc/ssl/certs/dddd
    SSLCertificateKeyFile /etc/ssl/private/dddd
    SSLCertificateChainFile /etc/ssl/certs/ddd
</VirtualHost>

<VirtualHost 172.20.30.40:80>
ServerName www.example.com
DocumentRoot /www/domain-80
    SSLCertificateFile /etc/ssl/certs/eeee
    SSLCertificateKeyFile /etc/ssl/private/eeee
    SSLCertificateChainFile /etc/ssl/certs/eee
</VirtualHost>

$ awk -v domain=www.example.com '$1 == "ServerName" {extract=($2 == domain)} extract && $1 ~ /^SSL/ {print $1 "=\"" $2 "\""}' vhost.conf 
SSLCertificateFile="/etc/ssl/certs/eeee"
SSLCertificateKeyFile="/etc/ssl/private/eeee"
SSLCertificateChainFile="/etc/ssl/certs/eee"

Erläuterung:

  • Das erste Pattern testet, ob der aktuelle Schlüssel "ServerName" ist und führt dann die Aktion aus:

  • Setze die Variable "extract" auf true (bzw. 1 in awk), falls der Name "www.example.com" ist.

  • Das zweite Pattern prüft, ob extrahiert werden soll und der aktuelle Schlüssel mit "SSL" anfängt.

  • Falls ja, gibt er eine Variablenzuweisung in Shell-Syntax aus.

Im Skript eingebaut dann:

1
eval $(awk -v domain=www.example.com '$1 == "ServerName" {extract=($2 == domain)} extract && $1 ~ /^SSL/ {print $1 "=\"" $2 "\""}' vhost.conf )

Und Du bekommst genau die Variablendeklarationen, die Du möchtest. Die awk-Variable "domain" habe ich deshalb eingeführt, weil man damit einfacher eine Eingabe oder ein Kommandozeilenargument in das awk-Skript bekommt:

1
2
3
# $1 enthält den Namen der Domain

eval $(awk -v "domain=$1" '$1 == "ServerName" {extract=($2 == domain)} extract && $1 ~ /^SSL/ {print $1 "=\"" $2 "\""}' vhost.conf )

Achtung: nicht das $1 vom Shell-Skript mit dem vom awk-Skript verwechseln!

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13213

Wenn Du einzeln extrahieren willst:

1
2
$ awk -v domain=www.example.com -v var=SSLCertificateKeyFile '$1 == "ServerName" {extract=($2 == domain)} extract && $1 == var {print $2}' vhost.conf 
/etc/ssl/private/eeee

Und noch eine Anmerkung: das funktioniert so nur, wenn "ServerName" vor den zu extrahierenden Werten steht. Sonst muss man das anders machen: dann merkt man sich alle Werte und macht die Ausgabe erst, wenn man "</VirtualHost>" liest. Das ist auf jeden Fall robuster, falls die Reihenfolge nicht festgelegt ist.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ cat vhost2.conf 
<VirtualHost 172.20.30.40:80>
DocumentRoot /www/domain-80
    SSLCertificateFile /etc/ssl/certs/dddd
    SSLCertificateKeyFile /etc/ssl/private/dddd
    SSLCertificateChainFile /etc/ssl/certs/ddd
ServerName sub2.example.com
</VirtualHost>

<VirtualHost 172.20.30.40:80>
DocumentRoot /www/domain-80
    SSLCertificateFile /etc/ssl/certs/eeee
    SSLCertificateKeyFile /etc/ssl/private/eeee
    SSLCertificateChainFile /etc/ssl/certs/eee
ServerName www.example.com
</VirtualHost>

$ awk -v domain=www.example.com -f x.awk vhost2.conf 
SSLCertificateFile="/etc/ssl/certs/eeee"
SSLCertificateChainFile="/etc/ssl/certs/eee"
SSLCertificateKeyFile="/etc/ssl/private/eeee"

Das awk-Skript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/<VirtualHost/ {delete data}

$1 == "ServerName" {server = $2}
$1 ~ /^SSL/ {data[$1] = $2}

/<\/VirtualHost>/ {
  if ( server == domain ) {
    for (var in data)
      printf "%s=\"%s\"\n", var, data[var]
  }
}

beLi3VeR

(Themenstarter)
Avatar von beLi3VeR

Anmeldungsdatum:
22. April 2006

Beiträge: 387

Klappt super, dich danke dir:

1
2
3
4
5
6
LC_DOMAIN="example.de"
LC_VHOSTS_PATH="/etc/apache2/sites-available/example.conf"

SSLCertificateFile=$(awk -v domain=$LC_DOMAIN -v var=SSLCertificateFile '$1 == "ServerName" {extract=($2 == domain)} extract && $1 == var {print $2}' $LC_VHOSTS_PATH)
SSLCertificateKeyFile=$(awk -v domain=$LC_DOMAIN -v var=SSLCertificateKeyFile '$1 == "ServerName" {extract=($2 == domain)} extract && $1 == var {print $2}' $LC_VHOSTS_PATH)
SSLCertificateChainFile=$(awk -v domain=$LC_DOMAIN -v var=SSLCertificateChainFile '$1 == "ServerName" {extract=($2 == domain)} extract && $1 == var {print $2}' $LC_VHOSTS_PATH)

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13213

beLi3VeR schrieb:

Klappt super, dich danke dir:

Prima! Zwecks Vermeidung von Redundanz würde ich das noch in eine Shell-Funktion auslagern:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
get_vhost_value(){
  awk -v domain=$LC_DOMAIN -v var=$1 '$1 == "ServerName" {extract=($2 == domain)} extract && $1 == var {print $2}' "$LC_VHOSTS_PATH"
}

LC_DOMAIN="example.de"
LC_VHOSTS_PATH="/etc/apache2/sites-available/example.conf"

SSLCertificateFile=$(get_vhost_value SSLCertificateFile)
SSLCertificateKeyFile=$(get_vhost_value SSLCertificateKeyFile)
SSLCertificateChainFile=$(get_vhost_value SSLCertificateChainFile)

beLi3VeR

(Themenstarter)
Avatar von beLi3VeR

Anmeldungsdatum:
22. April 2006

Beiträge: 387

Danke jetzt muss ich nur noch das script um Argumente erweitern

./script.sh -d example.de -p /path/

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Im Grunde kann man sich die ganze Schreiberei doch sparen ...

Denn die Variablen sollen ja genau so heißen und zugewiesen werden, wie sie in der Konfigurationsdatei stehen.
→ Also bräuchte man sie doch nur zu Bash-Variablenzuweisungen umformatieren und dann mit source ausführen ...?

Sicherheitsprobleme (das wäre hier ein Angelpunkt !) würde ich hier auch nicht erwarten, solange kein Code von außen zugeführt wird.


Konkret vereinfacht sich der awk-Teil damit auf einen Dreizeiler:

track@track:~$ echo '<VirtualHost 172.20.30.40:80>
DocumentRoot /www/domain-80
    SSLCertificateFile /etc/ssl/certs/dddd
    SSLCertificateKeyFile /etc/ssl/private/dddd
    SSLCertificateChainFile /etc/ssl/certs/ddd
ServerName sub2.example.com
</VirtualHost>

<VirtualHost 172.20.30.40:80>
DocumentRoot /www/domain-80
    SSLCertificateFile /etc/ssl/certs/eeee
    SSLCertificateKeyFile /etc/ssl/private/eeee
    SSLCertificateChainFile /etc/ssl/certs/eee
ServerName www.example.com
</VirtualHost>'  |  awk -v name="www.example.com" '
/SSLCert/         {text= text $1 "=\"" $2 "\"\n"} 
/ServerName/      {server=$2} 
/<\/VirtualHost>/ {if(server==name) printf "%s",text; text=""}'
SSLCertificateFile="/etc/ssl/certs/eeee"
SSLCertificateKeyFile="/etc/ssl/private/eeee"
SSLCertificateChainFile="/etc/ssl/certs/eee" 

Das wären ja schon mal die gewünschten Variablenzuweisungen für die Shell.

Nun wäre das ganze noch zu sourcen, dann hätten wir es:

track@track:~$ . <( awk -v name="www.example.com" '
/SSLCert/         {text= text $1 "=\"" $2 "\"\n"} 
/ServerName/      {server=$2} 
/<\/VirtualHost>/ {if(server==name) printf "%s",text; text=""}'  "vhost2.conf"  )  
track@track:~$ #   testen wir die Variablen:
track@track:~$ for v in "${!SSLCert@}"; do  echo "$v   enthält:   ${!v}";  done
SSLCertificateChainFile   enthält:   /etc/ssl/certs/eee
SSLCertificateFile   enthält:   /etc/ssl/certs/eeee
SSLCertificateKeyFile   enthält:   /etc/ssl/private/eeee 

(An dieser Stelle werden Servername und Dateiname eingekoppelt, gerne auch durch Shell-Variablen)

Soweit mal die Variante per source ... (die eigentlich ganz übersichtlich ist)

LG,

track

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13213

track schrieb:

Denn die Variablen sollen ja genau so heißen und zugewiesen werden, wie sie in der Konfigurationsdatei stehen.
→ Also bräuchte man sie doch nur zu Bash-Variablenzuweisungen umformatieren und dann mit source ausführen ...?

Das hat ich ja mit dem eval gemacht. Man muss aber die vom passenden Server auswählen.

Ich sehe gerade, bei der Lösung mit eval fehlen noch Anführungsstriche. Das muss so

1
eval "$(awk ...)"

Nun wäre das ganze noch zu sourcen, dann hätten wir es:

Ich nehme da lieber eval weil man dann nicht das bash-spezifische <( befehl ) braucht.

Soweit mal die Variante per source ... (die eigentlich ganz übersichtlich ist)

Deine Lösung geht auch mit eval.

Antworten |