Files @ ea69b2719d8e
Branch filter:

Location: majic-ansible-roles/docs/rolereference.rst

ea69b2719d8e 83.5 KiB text/prs.fallenstein.rst Show Annotation Show as Raw Download as Raw
branko
MAR-22: Implemented tests for the common role:

- Added missing documentation for pipreqcheck_uid and pipreqcheck_gid
parameters.
- Use static-hashed passwords for reproducibility during testing in test
playbook.
- Install Emacs and libmariadb-client-lgpl-dev-compat via test playbook on one
of the testing instances in order to test related tasks.
- Fixed parameter for connection limitting in test playbook.
- Added explicit parameters to test playbook for pipreqcheck_gid and
pipreqcheck_uid.
- Fixed deployment of ferm configuration file ot include setting user/group and
mode.
- Added tests covering common deployment, deployment when only mandatory
parameters are provided, and deployment when optional parameters are set as
well.
   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
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
.. _rolereference:

Role Reference
==============


Common parameters
-----------------

A number of common parameters are used by all of the roles during
deployment. This section lists such parameters.

**enable_backup** (boolean, optional, ``False``)
  If set to ``True``, and the role supports backups, server will be configured
  for back-up of role's data. See role description for more details on what is
  backed-up and if the option is available. Just keep in mind that if you enable
  this globally, all the roles will be running backup-specific tasks. If the
  option has been enabled, the ``backup_client`` role will be included
  automatically (see the role reference for details on parameters that need to
  be provided in the case).

**tls_private_key_dir** (string, optional if paths to private keys for all roles are explicitly specified)
  Path to directory on Ansible host that contains the private keys used by
  services deployed by various roles. When TLS keys are not explicitly defined
  in a role, this is the directory where the TLS key will be looked-up during
  Ansible run. Expected filename pattern is ``FQDN_SERVICE.key`` (for example,
  ``mail.example.com_smtp.key`` or ``xmpp.example.com_xmpp.key``).

**tls_certificate_dir** (string, optional if paths to certificate files for all roles are explicitly specified)
  Path to directory on Ansible host that contains the X.509 certificate files
  used by services deployed by various roles. When X.509 certificate is not
  explicitly defined in a role, this is the directory where the X.509
  certificate will be looked-up during Ansible run. Expected filename pattern is
  ``FQDN_SERVICE.pem`` (for example, ``mail.example.com_smtp.pem`` or
  ``xmpp.example.com_xmpp.pem``).


Preseed
-------

The ``preseed`` role can be used for generating simple preseed files for Debian
Wheezy installations.

The generated preseed files allow simplified installation, with a single root
partition. There is a number of parameters that allow for customising the
content of preseed files.

It is possible to specify parameter values that should be used for all servers,
as well for individual servers. It is also possible to combine this approach,
defining global parameters that get overridden per server.

The role will by default process all hosts from the inventory, generating one
preseed file per server.


Parameters
~~~~~~~~~~

**ansible_key** (string, optional, ``{{ lookup('file', '~/.ssh/id_rsa.pub') }}``)
  SSH public key that should be deployed to authorized_keys truststore for
  operating system user ``root``. This is necessary for the bootstrap process
  to work since Debian Jessie does not allow password-based logins for root.

**preseed_country** (string, optional, ``SE``)
  Country.

**preseed_directory** (string, optional, ``../preseed_files/``)
  Destination directory where the preseed files should be stored.

  .. warning::
     Do not name this directory ``preseed`` if it lies on a path where Ansible
     would normally look-up the roles (it will conflict with the role name).

**preseed_dns** (string, mandatory if **preseed_network_auto** is ``no``)
  Comma-separated list of DNS servers.

**preseed_domain** (string, mandatory if **preseed_network_auto** is ``no``)
  Server domain.

**preseed_gateway** (string, mandatory if **preseed_network_auto** is ``no``)
  Default gateway for the server.

**preseed_hostname** (string, mandatory if **preseed_network_auto** is ``no``)
  Server hostname.

**preseed_ip** (string, mandatory if **preseed_network_auto** is ``no``)
  IP address for the server network interface.

**preseed_keymap** (string, optional, ``us``)
  Keymap.

**preseed_language** (string, optional, ``en``)
  Language.

**preseed_locale** (string, optional, ``en_US.UTF-8``)
  Locale.

**preseed_mirror_directory** (string, optional, ``/debian``)
  Directory under which the Debian apt repositories can be found on the
  specified mirror.

**preseed_mirror_hostname** (string, optional, ``ftp.se.debian.org``)
  Resolvable hostname of FQDN where the Debian apt repositories can be
  found. Only HTTP mirrors are supported.

**preseed_mirror_proxy** (string, optional, ``None``)
  An HTTP proxy that should be used for accessing the Debian apt
  repositories.

**preseed_netmask** (string, mandatory if **preseed_network_auto** is ``no``)
  Netmask for the server network interface.

**preseed_network_auto** (boolean, optional, ``yes``)
  Specifies whether the network configuration should be automatic (using DHCP)
  or manual. If manual configuration is selected a number of additional options
  needs to be specified: ``preseed_hostname``, ``preseed_domain``,
  ``preseed_ip``, ``preseed_netmask``, ``preseed_gateway``,
  ``preseed_dns``. For some of these values you may want to use per-server
  overrides - see parameter ``preseed_server_overrides``.

**preseed_network_interface** (string, optional, ``eth0``)
  Name of network interface (for example ``eth0``, ``eth1`` etc) that should be
  configured.

**preseed_root_password** (string, optional, ``root``)
  Initial password that should be set for the server during the installation.

**preseed_server_overrides** (string, optional, ``{}``)
  A dictionary consisting out of one or more entries where individual values for
  preseed files can be overridden per-server. Each entry's key should be the
  name of the server, as specified in the inventory. Each value should also be a
  dictionary, where valid keys are: ``country``, ``dns``, ``domain``,
  ``gateway``, ``hostname``, ``ip``, ``keymap``, ``language``, ``locale``,
  ``mirror_directory``, ``mirror_hostname``, ``mirror_proxy``, ``netmask``,
  ``network_auto``, ``network_interface``, ``root_password``,
  ``timezone``. These have the same meaning as their ``preseed_`` counterparts.

**preseed_timezone** (string, optional, ``Europe/Stockholm``)
  Timezone that should be used when calculating server time. It is assumed that
  the local hardware clock is set to UTC.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)
- Debian 9 (Stretch)


Examples
~~~~~~~~

Here is an example configuration for a preseed file that sets some global
defaults to be used for all servers, and then overrides it for one server:

.. code-block:: yaml

  ---

  ansible_key: {{ lookup('file', '~/.ssh/id_rsa.pub') }}
  preseed_country: UK
  preseed_directory: /var/www/preseed
  preseed_keymap: UK
  preseed_language: en
  preseed_locale: en_UK.UTF-8
  preseed_mirror_directory: /debian
  preseed_mirror_hostname: ftp.uk.debian.org
  preseed_mirror_proxy: ""
  preseed_network_auto: yes
  preseed_network_interface: eth0
  preseed_root_password: secret
  preseed_timezone: Europe/London
  preseed_server_overrides:
    ldap.example.com:
      network_auto: no
      hostname: ldap
      domain: example.com
      ip: 192.168.1.20
      netmask: 255.255.255.0
      gateway: 192.168.1.1
      dns: 192.168.1.1,192.168.1.2
      timezone: Europe/Stockholm


Bootstrap
---------

The ``bootstrap`` role can be used for bootstraping a new server with
Ansible. In order to apply this role to a server, all that is necessary is root
access to the server (either via SSH or locally).

The role implements the following:

* Installs sudo package.
* Creates operating system user and group for Ansible (``ansible``).
* Sets-up an authorized_key for operating system user ``ansible`` (for remote
  SSH access).
* Configures sudo to allow operating system user ``ansible`` to run sudo
  commands without password authentication.
* Removes the Ansible user's key from the list of authorized keys for user root
  at the end of bootstrap process. This key was necessary only for the bootstrap
  process.


Parameters
~~~~~~~~~~

**ansible_key** (string, optional, ``{{ lookup('file', '~/.ssh/id_rsa.pub') }}``)
  SSH public key that should be deployed to authorized_keys truststore for
  operating system user ``ansible``.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)
- Debian 9 (Stretch)


Examples
~~~~~~~~

Since the role is meant to be used just after the server has been installed, and
using the ``root`` account, it is probably going to be invoked from a separate
playbook.

For example, a playbook (``bootstrap.yml``) could look something similar to:

.. code-block:: yaml

  ---

  - hosts: "{{ server }}"
    remote_user: root
    roles:
      - bootstrap
    vars:
      ansible_key: "{{ lookup('file', 'authorized_keys/ansible.pub') }}"

With such a playbook in place, it would be invoked with:

  ansible-playbook --ask-pass -e server=test1.example.com bootstrap.yml


Common
------

The ``common`` role can be used for applying a common configuration and
hardening across all servers, no matter what services they provide.

The role implements the following:

* Configures apt to use caching proxy (if any was specified).
* Sets-up umask for all logins to ``0027``.
* Installs sudo.
* Sets-up uniform bash prompt for all accounts (optionally coloured and with
  identifier). This is useful for distinguishing machines and/or environments.
* Sets-up ability to have user-specific ``/etc/profile.d/`` entries via
  ``$HOME/.profile.d/``.
* Installs additional base packages, as configured.
* Disables ``electric-indent-mode`` in Emacs globally if either the ``emacs24``
  or ``emacs24-nox`` are installed through the role.
* Creates additional operating system groups, as configured.
* Creates additional operating system users, as configured.
* Hardens the SSH server by disabling remote ``root`` logins and password-based
  authentication.
* Allows traversing of directory ``/etc/ssl/private/`` to everyone. This lets
  you put TLS private keys in central location where any operating system user
  can reach them provided they have appropriate read/write rights on the file
  itself, and provided they know the exact path of the file.
* Deploys CA certificate files, normally used for truststore purposes, to
  ``/usr/local/share/ca-certificates/``.
* Installs ``ferm`` (for iptables management), configuring a basic firewall
  which allows ICMP echo requests (PING), incoming connection on TCP port 22
  (SSH), and also introduces rate-limitting for incoming ICMP echo request
  pacakges and (new) TCP connections. The rate-limitting is based on the source
  IP address, using the ``iptables hashlimit`` module.
* Sets-up system for performing checks on certificates (currently only if they
  expire within less than 30 days). Roles that want their certificates checked
  should deploy a ``.conf`` to directory ``/etc/check_certificate/`` with paths
  to certificate files, one per line. Certificates are checked on daily basis.
* Deploys ``apticron`` package that performs checks for available package
  upgrades on daily basis. Mails are delivered to local ``root`` account, and
  can be redirected elsewhere via aliases. If using ``mail_forwarder`` or
  ``mail_server`` roles on the same server, aliases can be set-up through them.
* Sets-up system for performing checks on pip requirements files. Roles that
  want their requirements files checked should create a sub-directory inside of
  ``/etc/pip_check_requirements_upgrades``, and place ``.txt`` and ``.in`` files
  inside (with same base name). The ``.txt`` files should be standard
  requirements files with fixed versions (the ones installed by the role). The
  ``.in`` files should contain only the top-level packages (no
  dependencies). Avoid hard-coding versions in the ``.in`` file unless really
  needed. For packages where you want to stick to stable/LTS version branch, you
  should be able to use ``~=`` operator (for example ``django~=1.8.0``. Checks
  are implemented via `pip-tools <https://github.com/jazzband/pip-tools>`_ and a
  custom script that outputs diffs if upgrades are available. Script is run via
  cronjob on hourly basis, and any output will be delivered to local ``root``
  user.


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **backup_client**


Backups
~~~~~~~

If the backup for this role has been enabled, the following paths are backed-up:

**/var/log**
  Log files from the system.

**/home**
  Home directory for regular users (this can be changed via role parameters).

**/root**
  Root user's home directory (this can be changed via role parameters).

**/etc/shadow**
  Operating system user passwords.

**/var/mail**
  Local user's mails.

**/var/spool/cron**
  Local user's cronjobs.


Parameters
~~~~~~~~~~

**apt_proxy** (string, optional, ``None``)
  URI of a caching proxy that should be used when retrieving the packages via
  apt.

**os_users** (list, optional, ``[]``)
  A list of operating system users that should be set-up on a server. Each item
  is a dictionary with the following options describing the user parameters:

  **name** (string, mandatory)
    Name of the operating system user that should be created. User's default
    group will have the same name as the user.

  **uid** (number, optional, ``whatever OS picks``)
    UID for the operating system user. User's default group will have a GID
    identical to the user's UID if specified. Otherwise user's default group
    will have OS-determined GID.

  **additional_groups** (list, optional, ``[]``)
    List of additional groups that a user should belong to.

  **authorized_keys** (list, optional, ``[]``)
    List of SSH public keys that should be deployed to user's authorized_keys
    truststore.

  **password** (string, optional, ``!`` - no password)
    Encrypted password that should be set for the user.

**os_groups** (list, optional, ``[]``)
  A list of operating system groups that should be set-up on a server. Each item
  is a dictionary with the following options describing the group parameters:

  **name** (string, mandatory)
    Name of the operating system group that should be created.

  **gid** (number, optional, ``whatever OS picks``)
    GID for the operating system group.

**common_packages** (list, optional, ``[]``)
  List of additional operating system packages that should be installed on the
  server. Each element of the list should be a simple string denoting the name
  of the package.

**ca_certificates** (list, optional, ``{}``)
  Dictionary containing the CA certificates to deploy. Keys are base filenames
  (**without extension**) to be used when placing a certificate file in
  directory ``/usr/local/share/ca-certificates/``, while values are
  corresponding content to be placed in the file.

**extra_backup_patterns** (list, optional, ``[ "/home", "/root" ]]``)
  List of additional globbing patterns defining additional files or directories
  that should be backed-up.

**incoming_connection_limit** (string, optional, ``3/second``)
  Rate at which the incoming ICMP echo-request packages and new TCP connections
  will be accepted at. The value should be specified in the same format as value
  for the ``iptables hashlimit`` option ``--hashlimit-upto``.

**incoming_connection_limit_burst** (string, optional, ``9``)
  Initial burst of packages that should be accepted when the client with
  distinct source IP address connects to the server for the first time (usually
  higher than ``incoming_connection_limit``), even if it would go above the
  specified connection limit.

**pipreqcheck_uid** (integer, optional, ``whatever OS picks``)
  UID for user running the pip requirements upgrade checks. User is created with
  name ``pipreqcheck``.

**pipreqcheck_gid** (integer, optional, ``whatever OS picks``)
  GID for user running the pip requirements upgrade checks. Group is created
  with name ``pipreqcheck``.

**prompt_colour** (string, optional, ``none``)
  Colour for showing the Bash prompt. Supported values are:

  ``black``, ``red``, ``green``, ``brown``, ``blue``, ``purple``, ``cyan``,
  ``light_gray``, ``dark_gray``, ``light_red``, ``light_green``, ``yellow``,
  ``light_blue``, ``light_purple``, ``light_cyan``, ``white``, ``none``.

  You should probably *not* use the ``black`` colour. Setting affects Bash
  shells *only*. Setting the value to ``none`` uses default terminal colour.

**prompt_id** (string, optional, ``NONE``)
  Optional identifier appended to regular Bash prompt, useful for visually
  identifying distinct environments. For example, if set to ``test``, resulting
  prompt will be similar to ``admin@web[test]:~$``. Setting affects Bash shells
  *only*.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)
- Debian 9 (Stretch)


Examples
~~~~~~~~

Here is an example configuration for setting-up some common users, groups, and
packages on all servers:

.. code-block:: yaml

  ---

  os_users:
    - name: admin
      uid: 1000
      additional_groups:
        - sudo
      authorized_keys:
        - "{{ lookup('file', '/home/admin/.ssh/id_rsa.pub') }}"
      password: '$6$AaJRWtqyX5pk$IP8DUjgY0y2zqMom9BAc.O9qHoQWLFCmEsPRCika6l/Xh87cp2SnlMywH0.r4uEcbHnoicQG46V9VrJ8fxp2d.'
    - name: john
      uid: 1001
      password: '$6$AaJRWtqyX5pk$IP8DUjgY0y2zqMom9BAc.O9qHoQWLFCmEsPRCika6l/Xh87cp2SnlMywH0.r4uEcbHnoicQG46V9VrJ8fxp2d.'

  os_groups:
    - name: localusers
      gid: 2500

  common_packages:
    - emacs23-nox
    - screen
    - debconf-utils

  ca_certificates:
    "truststore": "{{ lookup('file', '../certs/truststore.pem') }}"

  incoming_connection_limit: 2/second

  incoming_connection_limit_burst: 6

  prompt_colour: light_green

  prompt_id: PROD

.. _ldap_client:

LDAP Client
-----------

The ``ldap_client`` role can be used for setting-up an OpenLDAP client on
destination machine.

The role implements the following:

* Installs OpenLDAP client tools.
* Sets-up global configuration file for OpenLDAP clients at /etc/ldap/ldap.conf.


Parameters
~~~~~~~~~~

**ldap_client_config** (list, optional, ``[]``)
  A list of configuration options that should be put into the LDAP configuration
  file. Each item is a dictionary with the following options defining the
  configuration parameter:

  **comment** (string, mandatory)
    Comment that will be shown in the file just above the configuration option.

  **option** (string, mandatory)
    Name of configuration option.

  **value** (string, mandatory)
    Value for configuration option.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for setting some common LDAP client options:

.. code-block:: yaml

  ---

  ldap_client_config:
    - comment: Set the base DN
      option: BASE
      value: dc=example,dc=com
    - comment: Set the default URI
      option: URI
      value: ldap://ldap.example.com/
    - comment: Set the truststore for TLS/SSL
      option: TLS_CACERT
      value: /etc/ssl/certs/example_ca.pem
    - commment: Force basic server certificate verification
      option: TLS_REQCERT
      value: demand
    - comment: Disable CRL checks for server certificate
      option: TLS_CRLCHECK
      value: none


LDAP Server
-----------

The ``ldap_server`` role can be used for setting-up an OpenLDAP server on
destination machine.

The role implements the following:

* Deploys LDAP TLS private key and certificate.
* Configures TLS versions and ciphers suppported by the server.
* Installs OpenLDAP server (package ``slapd``).
* Configures OpenLDAP server (base DN - domain, organisation, TLS, SSF, log levels).
* Sets-up separate log file for OpenLDAP server at ``/var/log/slapd.log`` (with
  log rotation included).
* Enables the ``misc`` LDAP schema (from ``/etc/ldap/schema/misc.ldif``). This
  is necessary for the mail server role.
* Enables the ``memberof`` overlay on top of default database. The overlay is
  configured to keep track of membership changes for object class
  ``groupOfUniqueNames`` via attribute ``uniqueMember``. Enforcement of
  referential integrity is turned on as well (modifications of ``memberof``
  attribute will update corresponding group as well.
* Creates a basic directory structure used by most of the other roles.
* Creates a basic directory structure used by the mail server role.
* Creates login entries for services that need to consume LDAP directory data in
  some way.
* Creates user-supplied groups in LDAP.
* Configures permissions.
* Creates LDAP entries.
* Configures firewall to allow incoming connections to the LDAP server (via both
  TCP 389 and 636).
* Sets the LDAP server administrator's password.


LDIF Templates
~~~~~~~~~~~~~~

For adding users, use::

  dn: uid=USERNAME,ou=people,BASE_DN
  objectClass: inetOrgPerson
  objectClass: simpleSecurityObject
  uid: USERNAME
  userPassword: PASSWORD_FROM_SLAPPASSWD
  cn: NAME SURNAME
  sn: SURNAME
  gn: NAME
  displayName: DISPLAYNAME
  initials: INITIALS
  mail: MAIL
  mobile: MOBILE



Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **common**
* **ldap_client**
* **backup_client**


Backups
~~~~~~~

If the backup for this role has been enabled, the following paths are backed-up:

**/srv/backup/slapd.bak**
  Dump of the LDAP database. LDAP database dump is created every day at 01:45 in
  the morning. This does *not* include the dump of the config database
  (``cn=config``).


Parameters
~~~~~~~~~~

**ldap_admin_password** (string, mandatory)
  Password for the default administrator account of LDAP server (the
  ``cn=admin,DOMAIN`` entry/user).

**ldap_entries** (list, optional, ``[]``)
  List of entries that should be kept in the LDAP directory. Each item is a
  dictionary describing a single LDAP entry, with all of its attributes
  listed. The keys in this dictionary should be the attribute names. The values
  should be either strings, for setting a single attribute value, or a list of
  strings if it is necessary to set multiple values for the same attribute.

**ldap_permissions** (list, optional, ``see below``)
  List of LDAP access rules to apply to base DN served by the LDAP server. The
  listed access control rules will *replace* all existing rules, and will be
  added in the same order they are listed in. Each item is a string that
  constitutes a single access control rule. The format should be the same as
  described in `OpenLDAP Administrator's Guide
  <http://www.openldap.org/doc/admin24/access-control.html#Access%20Control%20via%20Dynamic%20Configuration>`.

  Default value is:

  .. code-block:: yaml

    - >
      to *
      by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
      by * break
    - >
      to attrs=userPassword,shadowLastChange
      by self write
      by anonymous auth
      by dn="cn=admin,BASEDN" write
      by * none
    - >
      to dn.base=""
      by * read
    - >
      to *
      by self write
      by dn="cn=admin,BASEDN" write
      by * none

**ldap_server_consumers** (list, optional, ``[]``)
  List of items describing additional login entries that should be created for
  services that want to be able to log-in into the LDAP server and consume the
  data present within. Each item should be a dictionary, with the following keys
  avaialable:

  - **name** (name of the service, mandatory, this will be used to construct the
    login entry DN in format of ``cn=NAME,ou=services,BASE_DN``)
  - **password** (password for the login entry, mandatory)
  - **state** (state of the service, optional, defaults to ``present``, this
    should be ``present`` or ``absent``, allowing for removal of old services)

**ldap_server_groups** (list, optional, ``[]``)
  List of groups that should be created in the LDAP directory. Each item should
  be a dictionary containing the following keys:

  - **name** (name of the group, mandatory, this will be used to construct the
    group DN in format of ``cn=NAME,ou=groups,BASE_DN``)
  - **state** (state of the group, optional, defaults to ``present``, this
    should be ``present`` or ``absent``, allowing for removal of old groups)

**ldap_server_domain** (string, optional, ``{{ ansible_domain }}``)
  Domain that should be used for constructing the base DN of default user LDAP
  database. This should be a sub-domain dedicated to organisation. The base DN
  will be constructed by putting all elements of the sub-domain as ``dc``
  entries (as per standard Debian convention). I.e. ``example.com`` would get
  transformed into ``dc=example,dc=com``.

**ldap_server_organization** (string, optional, ``Private``)
  Organization that should be specified in the base DN entry.

**ldap_server_log_level** (string, optional, ``256``)
  Log level to use for the server. This should be compatible with OpenLDAP
  configuration option ``olcLogLevel``. See `OpenLDAP Administrator's Guide
  <http://www.openldap.org/doc/admin24/slapdconf2.html#cn=config>` for value
  description and syntax.

**ldap_server_tls_certificate** (string, optional, ``{{ lookup('file', tls_certificate_dir + '/' ansible_fqdn + '_ldap.pem') }}``)
  X.509 certificate used for TLS for LDAP service. The file will be stored in
  directory ``/etc/ssl/certs/`` under name ``{{ ansible_fqdn }}_ldap.pem``.

**ldap_server_tls_key** (string, optional, ``{{ lookup('file', tls_private_key_dir + '/' ansible_fqdn + '_ldap.key') }}``)
  Private key used for TLS for LDAP service. The file will be stored in
  directory ``/etc/ssl/private/`` under name ``{{ ansible_fqdn }}_ldap.key``.

**ldap_server_ssf** (number, optional, ``128``)
  Minimum *Security Strength Factor* to require from all incoming
  connections. This applies for both remote and local connections.

**ldap_tls_ciphers** (string, optional ``NONE:+VERS-TLS1.2:+CTYPE-X509:+COMP-NULL:+SIGN-RSA-SHA256:+SIGN-RSA-SHA384:+SIGN-RSA-SHA512:+DHE-RSA:+ECDHE-RSA:+SHA256:+SHA384:+AEAD:+AES-128-GCM:+AES-128-CBC:+AES-256-GCM:+AES-256-CBC:+CURVE-ALL``)
  TLS ciphers to enable on the LDAP server. This should be a GnuTLS-compatible
  cipher specification that should also include what TLS protocol versions
  should be used. Value should be compatible with OpenLDAP server option
  ``olcTLSCipherSuite``. Default value allows only TLSv1.2 and strong PFS
  ciphers.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for setting-up LDAP server:

.. code-block:: yaml

  ---

  ldap_server_domain: "example.com"
  ldap_server_organization: "Example Corporation"
  ldap_server_log_level: 256
  ldap_server_tls_certificate: "{{ lookup('file', '~/tls/ldap.example.com_ldap.pem') }}"
  ldap_server_tls_key: "{{ lookup('file', '~/tls/ldap.example.com_ldap.key') }}"
  ldap_server_ssf: 128

  ldap_permissions:
    - >
      to *
      by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
      by * break
    - >
      to attrs=userPassword,shadowLastChange
      by self write
      by anonymous auth
      by dn="cn=admin,dc=example,dc=com" write
      by * none
    - >
      to dn.base=""
      by * read
    - >
      to *
      by self write
      by dn="cn=admin,dc=example,dc=com" write
      by users read
      by * none

  ldap_entries:
    - dn: ou=people,dc=example,dc=com
      objectClass: organizationalUnit
      ou: people
    - dn: ou=groups,dc=example,dc=com
      objectClass: organizationalUnit
      ou: groups
    - dn: uid=john,dc=example,dc=com
      objectClass:
        - inetOrgPerson
        - simpleSecurityObject
      userPassword: somepassword
      uid: john
      cn: John Doe
      sn: Doe


XMPP Server
-----------

The ``xmpp_server`` role can be used for setting-up Prosody, an XMPP server, on
destination machine.

The role implements the following:

* Sets-up the Prosody apt repository.
* Deploys XMPP TLS private key and certificate.
* Installs Prosody.
* Configures Prosody.
* Configures firewall to allow incoming connections to the XMPP server.

Prosody is configured as follows:

* Modules enabled: roster, saslauth, tls, dialback, posix, private, vcard,
  version, uptime, time, ping, pep, register, admin_adhoc, announce, legacyauth.
* Self-registration is not allowed.
* TLS is configured. Legacy TLS is available on port 5223.
* Client-to-server communication requires encryption (TLS).
* Authentication is done via LDAP. For setting the LDAP TLS truststore, see
  :ref:`LDAP Client <ldap_client>`.
* Internal storage is used.
* For each domain specified, a dedicated conference/multi-user chat (MUC)
  service is set-up, with FQDN set to ``conference.DOMAIN``.
* For each domain specified, a dedicated file proxy service will be set-up, with
  FQDN set to ``proxy.DOMAIN``.

.. warning::
   Since it is not possible to set-up separate TLS configuration for *c2s* and
   *s2s* connections in Prosody 0.9.x, no hardening of TLS is performed in order
   to improve interoperability. This will be changed in Prosody 0.10.x, at which
   point hardening can be revisited.

Prosody expects a specific directory structure in LDAP when doing look-ups:

* Prosody will log-in to LDAP as user
  ``cn=prosody,ou=services,XMPP_LDAP_BASE_DN``.
* User entries are read from sub-tree (first-level only)
  ``ou=people,XMPP_LDAP_BASE_DN``. Query filter used for finding users is
  ``(&(mail=$user@$host)(memberOf=cn=xmpp,ou=groups,XMPP_LDAP_BASE_DN))``. This
  allows group-based granting of XMPP service to users.


LDIF Templates
~~~~~~~~~~~~~~

For adding user to a group, use::

  dn: cn=xmpp,ou=groups,BASE_DN
  changetype: modify
  add: uniqueMember
  uniqueMember: uid=USERNAME,ou=people,BASE_DN


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **common**
* **backup_client**


Backups
~~~~~~~

If the backup for this role has been enabled, the following paths are backed-up:

**/var/lib/prosody/**
  Roster information, as well as undelivered (offline) messages for all XMPP
  users. Keep in mind that list of available users and their credentials are
  stored in the LDAP directory (which is backed-up via LDAP server role).


Parameters
~~~~~~~~~~

**xmpp_administrators** (list, mandatory)
  List of Prosody users that should be granted administrator privileges over
  Prosody. Each item is a string with value equal to XMPP user ID
  (i.e. ``john.doe@example.com``).

**xmpp_domains** (list, optional, ``{{ ansible_domain }}``)
  List of domains that are served by this Prosody instance. Each item is a
  string specifying a domain.

**xmpp_ldap_base_dn** (string, mandatory)
  Base DN on the LDAP server. A specific directory structure is expected under
  this entry (as explained above) in order to locate the available domains,
  users, aliases etc.

**xmpp_ldap_password** (string, mandatory)
  Password used for authenticating to the LDAP server.

**xmpp_ldap_server** (string, mandatory)
  Fully qualified domain name, hostname, or IP address of the LDAP server used
  for user authentication and listing.

**xmpp_tls_certificate** (string, optional, ``{{ lookup('file', tls_certificate_dir + '/' + fqdn + '_xmpp.pem') }}``)
  X.509 certificate used for TLS for XMPP service. The file will be stored in
  directory ``/etc/ssl/certs/`` under name ``{{ ansible_fqdn }}_xmpp.pem``.

**xmpp_tls_key** (string, optional, ``{{ lookup('file', tls_private_key_dir + '/' + fqdn + '_xmpp.key') }}``)
  Private key used for TLS for XMPP service. The file will be stored in
  directory ``/etc/ssl/private/`` under name ``{{ ansible_fqdn }}_xmpp.key``.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for setting-up XMPP server using Prosody:

.. code-block:: yaml

  ---

  xmpp_administrators:
    - john.doe@example.com
  xmpp_domains:
    - example.com
  xmpp_ldap_base_dn: dc=example,dc=com
  xmpp_ldap_password: xmpp
  xmpp_ldap_server: ldap.example.com
  # These are default key and certificate that generated during Prosody
  # installation. Possibly you want to deploy your own.
  xmpp_tls_key: "{{ lookup('file', '/etc/prosody/certs/localhost.key') }}"
  xmpp_tls_certificate: "{{ lookup('file', '/etc/prosody/certs/localhost.crt') }}"


Mail Server
-----------

.. warning::
   It may happen that the ``clamav-freshclam`` service hasn't finished
   downloading the virus database before the ``clamav-daemon`` and
   ``clamav-milter`` services are enabled during the initial run. If mail server
   is not operational, you may need to wait for a little while for download to
   finish, and then restart the ``clamav-daemon`` and ``clamav-milter``
   services.

The ``mail_server`` role can be used for setting-up a complete mail server
solution, which includes both SMTP and IMAP service, on destination machine.

Postfix is used SMTP, while Dovecot is used for IMAP.

The role implements the following:

* Installs rsync.
* Deploys IMAP/SMTP TLS private keys and certificates.
* Installs and configures Dovecot, Postfix, ClamAV, and ClamAV Milter.
* Purges Exim4 configuration (just in case).
* Sets-up aliases for the local recipients.
* Installs SWAKS (utility for testing SMTP servers).
* Sets-up the necessary directories and files under Postfix chroot.
* Configures firewall to allow incoming connections to the mail server. This
  includes set-up of redirection from TCP port 26 to TCP port 587 (alternate
  SMTP submission port to work around common network blocks).

Deployed services are configured as follows:

* Both Postfix and Dovecot look-up available domains, users, and aliases in
  LDAP.
* Incoming and outgoing mail is scanned with ClamAV (via ClamAV
  Milter). Infected mails are rejected.
* Mail is stored in directory ``/var/MAIL_USER/DOMAIN/USER``, using ``Maildir``
  format.
* TLS is required for user log-ins for both SMTP and IMAP.
* For user submission (SMTP), users must connect and authenticate over TCP
  port 587.
* Configures TLS versions and ciphers supported by Dovecot.
* Configures TLS versions and ciphers supported by Postfix on submission port
  (587). TLS configuration on port 25 is kept intact in order to maintain maximum
  interoperability with other servers.
* RBL's are used for combating spam (if any is specified in configuration, see
  below).
* Postfix is configured to deliver undeliverable bounces to postmaster. This
  helps with detecting misconfigured applications and servers.

Both Postfix and Dovecot expect a specific directory structure in LDAP when
doing look-ups:

* Postfix will log-in to LDAP as user
  ``cn=postfix,ou=services,MAIL_LDAP_BASE_DN``.
* Dovecot will log-in to LDAP as user
  ``cn=dovecot,ou=services,MAIL_LDAP_BASE_DN``.
* Domain entries need to be available as
  ``dc=DOMAIN,ou=domains,ou=mail,ou=services,MAIL_LDAP_BASE_DN``.
* Alias entries need to be available as
  ``cn=ALIAS,ou=aliases,ou=mail,ou=services,MAIL_LDAP_BASE_DN``.
* User entries are read from sub-tree (first-level only)
  ``ou=people,MAIL_LDAP_BASE_DN``. Query filter used for finding users is
  ``(&(mail=%s)(memberOf=cn=mail,ou=groups,MAIL_LDAP_BASE_DN))``. This allows
  group-based granting of mail services to users.


LDIF Templates
~~~~~~~~~~~~~~

For adding domains, use::

  dn: dc=DOMAIN,ou=domains,ou=mail,ou=services,BASE_DN
  objectClass: dNSDomain
  dc: DOMAIN

For adding aliases, use::

  dn: cn=ALIAS,ou=aliases,ou=mail,ou=services,BASE_DN
  objectClass: nisMailAlias
  cn: ALIAS
  rfc822MailMember: REALEMAIL

For adding user to a group, use::

  dn: cn=mail,ou=groups,BASE_DN
  changetype: modify
  add: uniqueMember
  uniqueMember: uid=USERNAME,ou=people,BASE_DN


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **common**
* **backup_client**


Backups
~~~~~~~

If the backup for this role has been enabled, the following paths are backed-up:

**/var/{{ mail_user }}**
  All data stored by the mail server, including mails and Sieve scripts. Keep in
  mind that list of available users and their credentials are stored in the LDAP
  directory (which is backed-up via LDAP server role).


Parameters
~~~~~~~~~~

**mail_ldap_base_dn** (string, mandatory)
  Base DN on the LDAP server. A specific directory structure is expected under
  this entry (as explained above) in order to locate the available domains,
  users, aliases etc.

**mail_ldap_url** (string, mandatory)
  LDAP URL that should be used for connecting to the LDAP server for doing
  domain/user look-ups.

**mail_ldap_tls_truststore** (string, optional, ``{{ lookup('file', tls_certificate_dir + '/truststore.pem') }}``)
  X.509 certificate chain used for issuing certificate for the LDAP service. The
  file will be stored in locations ``/etc/ssl/certs/mail_ldap_tls_truststore.pem``
  and ``/var/spool/postfix/etc/ssl/certs/mail_ldap_tls_truststore.pem``.

**mail_ldap_postfix_password** (string, mandatory)
  Password for authenticating the Postfix LDAP user.

**mail_ldap_dovecot_password** (string, mandatory)
  Password for authenticating the Dovecot LDAP user.

**mail_server_tls_protocols** (list, optional, ``[ "TLSv1.2" ]``)
  List of TLS protocols the mail server should support. Each value specified
  should be compatible with Postfix configuration option
  ``smtpd_tls_mandatory_protocols`` and Dovecot configuration option
  ``ssl_protocols``.

**mail_server_tls_ciphers** (string, optional ``DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:!aNULL:!MD5:!EXPORT``)
  TLS ciphers to enable on the mail server (for IMAP and SMTP submission). This
  should be an OpenSSL-compatible cipher specification. Value should be
  compatible with Postfix configuration option ``tls_high_cipherlist`` and
  Dovecot configuration option ``ssl_cipher_list``. Default value allows only
  TLSv1.2 and strong PFS ciphers.

**mail_user** (string, optional, ``vmail``)
  Name of the user that owns all the mail files.

**mail_user_uid** (integer, optional, ``whatever OS picks``)
  UID of the user that owns all the mail files.

**mail_user_gid** (integer, optional, ``whatever OS picks``)
  GID of the user that owns all the mail files.

**imap_max_user_connections_per_ip** (integer, optional, ``10``)
  Maximum number of IMAP connections from a single IP for a single user. Default
  value can be considered rather low, since two devices (computer and phone)
  will easily reach it.

**imap_tls_certificate** (string, optional, ``{{ lookup('file', tls_certificate_dir + '/' ansible_fqdn + '_imap.pem') }}``)
  X.509 certificate used for TLS for IMAP service. The file will be stored in
  directory ``/etc/ssl/certs/`` under name ``{{ ansible_fqdn }}_imap.pem``.

**imap_tls_key** (string, optional, ``{{ lookup('file', tls_private_key_dir + '/' ansible_fqdn + '_imap.key') }}``)
  Private key used for TLS for IMAP service. The file will be stored in
  directory ``/etc/ssl/private/`` under name ``{{ ansible_fqdn }}_imap.key``.

**local_mail_aliases** (dictionary, optional, ``[]``)
  Dictionary defining the local aliases. Aliases defined this way will either be
  appended to default aliases on the server, or replace the existing entries (if
  the alias/recipient is already present). Keys in the dictionary are the local
  recipients/aliases, while the value provided should be a space-separated list
  of mail addresses (or local users) where the mails should be forwarded.

**smtp_tls_certificate** (string, optional, ``{{ lookup('file', tls_certificate_dir + '/' ansible_fqdn + '_smtp.pem') }}``)
  X.509 certificate used for TLS for SMTP service. The file will be stored in
  directory ``/etc/ssl/certs/`` under name ``{{ ansible_fqdn }}_smtp.pem``.

**smtp_tls_key** (string, optional, ``{{ lookup('file', tls_private_key_dir + '/' ansible_fqdn + '_smtp.key') }}``)
  Private key used for TLS for SMTP service. The file will be stored in
  directory ``/etc/ssl/private/`` under name ``{{ ansible_fqdn }}_smtp.key``.

**imap_folder_separator** (string, optional, ``/``)
  Character used for separating the IMAP folders when clients are requesting
  listing from the server. Usually either slash(``/``) or dot(``.``).

**smtp_rbl** (list, optional, ``[]``)
  List of RBLs to use for detecting servers which send out spam. Each item is a
  string resembling the RBL domain.

**mail_postmaster** (string, optional, ``postmaster@{{ ansible_domain}}``)
  Mail address to use for the postmaster account in Dovecot.

**smtp_allow_relay_from** (list, optional, [])
  List of networks from which mail relaying is allowed even without
  authentication. Each item in the list is a string defining a network. The
  format must be compatible with Postfix ``mynetworks`` setting (for example:
  ``192.168.1.0/24``, ``myhost.example.com`` etc).


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for setting-up XMPP server using Prosody:

.. code-block:: yaml

  ---

  mail_ldap_url: ldap://ldap.example.com/
  mail_ldap_tls_truststore: /etc/ssl/certs/truststore.pem
  mail_ldap_base_dn: dc=example,dc=com
  mail_ldap_postfix_password: postfix
  mail_ldap_dovecot_password: dovecot

  mail_user: vmail
  mail_user_uid: 5000
  mail_user_gid: 5000

  # All mails sent to local user root will be forwarded to external account as
  # well.
  local_mail_aliases:
    root: "root john.doe@example.com"

  imap_tls_certificate: "{{ lookup('file', '~/tls/mail.example.com_imap.pem') }}"
  imap_tls_key: "{{ lookup('file', '~/tls/mail.example.com_imap.key') }}"
  smtp_tls_certificate: "{{ lookup('file', '~/tls/mail.example.com_smtp.pem') }}"
  smtp_tls_key: "{{ lookup('file', '~/tls/mail.example.com_smtp.key') }}"
  imap_folder_separator: /
  smtp_rbl:
    - bl.spamcop.net
    - zen.spamhaus.org
  mail_postmaster: postmaster@example.com

  smtp_allow_relay_from:
    - ldap.example.com
    - xmpp.example.com

  imap_max_user_connections_per_ip: 50


Mail Forwarder
--------------

The ``mail_forwarder`` role can be used for setting-up a local SMTP server for
sending out mails and receiving mails for local users. The SMTP server is
provided by Postfix.

SMTP service on server set-up this way is not meant to be exposed to the
Internet directly, and should receive delivery failures from the relay server
instead.

The role implements the following:

* Installs and configures Postfix.
* Purges Exim4 configuration (just in case).
* Sets-up aliases for the local recipients.
* Installs SWAKS (utility for testing SMTP servers).
* Configures firewall to accept SMTP connections from SMTP relay (if one has
  been configured). This allows for delivery of bounced e-mails.

Postfix is configured as follows:

* Local destinations are set-up.
* A relay host is set.
* TLS is enforced for relaying mails, with configurable truststore for server
  certificate verification if SMTP relay is used. If SMTP relay is not used
  (configured), no certificate verification is done.


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **common**


Parameters
~~~~~~~~~~

**local_mail_aliases** (dictionary, optional, ``[]``)
  Dictionary defining the local aliases. Aliases defined this way will either be
  appended to default aliases on the server, or replace the existing entries (if
  the alias/recipient is already present). Keys in the dictionary are the local
  recipients/aliases, while the value provided should be a space-separated list
  of mail addresses (or local users) where the mails should be forwarded.

**smtp_relay_host** (string, optional, ``None``)
  SMTP server via which the mails are sent out for non-local recipients.

**smtp_relay_truststore** (string, optional, ``{{ lookup('file', tls_certificate_dir + '/truststore.pem') }}``)
  X.509 certificate chain used for issuing certificate for the SMTP relay
  service. The file will be stored in location
  ``/etc/ssl/certs/smtp_relay_truststore.pem``


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)
- Debian 9 (Stretch)


Examples
~~~~~~~~

Here is an example configuration for setting-up the mail forwarder:

.. code-block:: yaml

  ---

  # All mails sent to local user root will be forwarded to external account as
  # well.
  local_mail_aliases:
    root: "root john.doe@example.com"

  smtp_relay_host: mail.example.com

  smtp_relay_truststore: /etc/ssl/certs/example_ca_chain.pem


Web Server
----------

The ``web_server`` role can be used for setting-up a web server on destination
machine.

The role is supposed to be very lightweight, providing a basis for deployment of
web applications.

The role implements the following:

* Installs and configures nginx with a single, default vhost with a small static
  index page.
* Deploys the HTTPS TLS private key and certificate (for default vhost).
* Configures TLS versions and ciphers supported by Nginx.
* Configures firewall to allow incoming connections to the web server.
* Installs and configures virtualenv and virtualenvwrapper as a common base for
  Python apps.
* Installs and configures PHP FPM as a common base for PHP apps.


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **common**


Parameters
~~~~~~~~~~

**default_enforce_https** (boolean, optional, ``True``)
  Specify if HTTPS should be enforced for the default virtual host or not. If
  enforced, clients connecting via plaintext will be redirected to HTTPS, and
  clients will be served with ``Strict-Transport-Security`` header with value of
  ``max-age=31536000; includeSubDomains``.

**default_https_tls_certificate** (string, optional, ``{{ lookup('file', tls_certificate_dir + '/' + ansible_fqdn + '_https.pem') }}``)
  X.509 certificate used for TLS for HTTPS service. The file will be stored in
  directory ``/etc/ssl/certs/`` under name ``{{ ansible_fqdn }}_https.pem``.

**default_https_tls_key** (string, optional, ``{{ lookup('file', tls_private_key_dir + '/' + ansible_fqdn + '_https.key') }}``)
  Private key used for TLS for HTTPS service. The file will be stored in
  directory ``/etc/ssl/private/`` under name ``{{ ansible_fqdn }}_https.key``.

**web_default_title** (string, optional, ``Welcome``)
  Title for the default web page shown to users (if no other vhosts were matched).

**web_default_message** (string, optional, ``You are attempting to access the web server using a wrong name or an IP address. Please check your URL.``)
  Message for the default web page shown to users (if no other vhosts were
  matched).

**web_server_tls_protocols** (list, optional, ``[ "TLSv1.2" ]``)
  List of TLS protocols the web server should support. Each value specified
  should be compatible with Nginx configuration option ``ssl_protocols``.

**web_server_tls_ciphers** (string, optional ``DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:!aNULL:!MD5:!EXPORT``)
  TLS ciphers to enable on the web server. This should be an OpenSSL-compatible
  cipher specification. Value should be compatible with Nginx configuration
  option ``ssl_ciphers``. Default value allows only TLSv1.2 and strong PFS
  ciphers.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for setting-up web server:

.. code-block:: yaml

  ---

  default_https_tls_key: "{{ lookup('file', inventory_dir + '/tls/web.example.com_https.key') }}"
  default_https_tls_certificate: "{{ lookup('file', inventory_dir + '/tls/web.example.com_https.pem') }}"

  web_default_title: "Welcome to Example Inc."
  web_default_message: "You are attempting to access the web server using a wrong name or an IP address. Please check your URL."


PHP Website
-----------

The ``php_website`` role can be used for setting-up a website powered by PHP on
destination machine.

This role is normally not supposed to be used directly, but should instead serve
as the basis for writing website-specific roles. Therefore the role is written
in quite generic way, allowing the integrator to write his/her own logic for
deploying the necessary PHP applications, while still reusing a common base and
reducing the workload.

The role implements the following:

* Creates a dedicated user/group for running the PHP scripts.
* Creates a dedicated administrator user for maintaining the website.
* Creates a base directory where the website-specific code and data should be
  stored at.
* Adds nginx to website's group, so nginx could read the necessary files.
* Adds website administrator to website's group, so administrator could manage
  the code and data.
* Installs additional packages required for running the role (as configured).
* Deploys the HTTPS TLS private key and certificate (for website vhost).
* Configures PHP FPM and nginx to serve the website.

The role is implemented with the following layout/logic in mind:

* Website users are named after the ``FQDN`` (fully qualified domain name) of
  website, in format of ``web-ESCAPEDFQDN``, where ``ESCAPEDFQDN`` is equal to
  ``FQDN`` where dots have been replaced by underscores (for example,
  ``web-cloud_example_com``).
* Website users are set-up via GECOS field to have their umask set to ``0007``
  (in combination with ``pam_umask``).
* Administrator users are named after the ``FQDN`` (fully qualified domain name)
  of website, in format of ``admin-ESCAPEDFQDN``, where ``ESCAPEDFQDN`` is equal
  to ``FQDN`` where dots have been replaced by underscores (for example,
  ``admin-cloud_example_com``).
* All websites reside within a dedicated sub-directory in ``/var/www``. The
  sub-directory name is equal to the ``FQDN`` used for accessing the
  website. Owner of the directory is set to be the application administrator,
  while group is set to be the website group. Additionally, ``SGID`` bit is set
  on the directory. This allows admin, with correct umask, to create necessary
  files and directories that should be readable (and eventually writeable) by
  the website user (running the PHP scripts) without having to become root.
* All files placed in the website directory should be either created there
  directly, or copied to the directory in order to make sure the ``SGID`` gets
  honored. **Do not move the files, the permissions will not be set correctly.**
* Within the website directory, nginx/php5-fpm will expect to find the relevant
  files within the htdocs sub-directory (this can be symlink too).
* nginx communicates with PHP FPM over a dedicated Unix socket for each website.


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **common**
* **web_server**


Parameters
~~~~~~~~~~

**additional_fpm_config** (dict, optional, ``{}``)
  Additional PHP FPM configuration options that should be included for PHP
  website's pool. Keys are parameter names, values are associated values. Don't
  forget to include quotes in the value itself if expected value type is string.

**additional_nginx_config** (list, optional, ``[]``)
  List providing additional Nginx configuration options to include. This can be
  useful for specifying things like error pages. Options are applied inside of a
  **server** context of Nginx configuration file.

  Each item is a dictionary with the following options describing the extra
  configuration option:

  **comment** (string, mandatory)
    Comment describing the configuration option.

  **value** (string, mandatory)
    Configuration option.

**admin_uid** (integer, optional, ``whatever OS picks``)
  UID of the dedicated website administrator user. The user will be member of
  website group.

**deny_files_regex** (list, optional, ``[]``)
  List of regular expressions for matching files/locations to which the web
  server should deny access. This is useful to block access to any sensitive
  files that should not be served directly by the web server. The format must be
  compatible with regular expressions used by ``nginx`` for ``location ~``
  syntax.

**enforce_https** (boolean, optional, ``True``)
  Specify if HTTPS should be enforced for the website or not. If enforced,
  clients connecting via plaintext will be redirected to HTTPS, and clients will
  be served with ``Strict-Transport-Security`` header with value of
  ``max-age=31536000; includeSubDomains``.

**environment_indicator** (dictionary, optional, ``null``)
  Specify configuration for including environment indicator on all HTML
  pages. Indicator is a simple strip at bottom of a page with custom background
  colour, text colour, and text.

  Specifying environment indicator is useful for avoiding mistakes when testing
  by having better visibility what environment you are in
  (production/staging/test).

  The following keys need to be specified:

  **background_colour** (string, mandatory)
    Background colour to use for the strip at bottom. This should be value
    compatible with CSS ``background-color`` attribute.

  **text_colour** (string, mandatory
    Text colour to use for the strip at bottom. This should be value compatible
    with CSS ``color`` attribute.

  **text** (string, mandatory)
    Text to show in show in the strip at bottom.

**fqdn** (string, mandatory)
  Fully-qualified domain name where the website is reachable. This value is used
  for calculating the user/group name for dedicated website user, as well as
  home directory of the website user (where data/code should be stored at).

**index** (string, optional, ``index.php``)
  Space-separated list of files which should be treated as index files by the
  web server. The web server will attempt opening these index files, in
  succession, until the first match, or until it runs out of matches, when a
  client requests an URI pointing to directory.

**https_tls_certificate** (string, optional, ``{{ lookup('file', tls_certificate_dir + '/' + fqdn + '_https.pem') }}``)
  X.509 certificate used for TLS for HTTPS service. The file will be stored in
  directory ``/etc/ssl/certs/`` under name ``{{ fqdn }}_https.pem``.

**https_tls_key** (string, optional, ``{{ lookup('file', tls_private_key_dir + '/' + fqdn + '_https.key') }}``)
  Private key used for TLS for HTTPS service. The file will be stored in
  directory ``/etc/ssl/private/`` under name ``{{ fqdn }}_https.key``.

**php_file_regex** (string, optional, ``\.php$``)
  Regular expression used for determining which file should be interepted via
  PHP.

**php_rewrite_urls** (list, optional, ``[]``)
  A list of rewrite rules that are applied to incoming requests. These rewrite
  rules are specifically targetted at prettying-up the URLs used by the PHP
  scripts. Each element of the list should be a string value compatible with the
  format of ``nginx`` option ``rewrite``. The keyword ``rewrite`` itself should
  be omitted, as well as trailing semi-colon (``;``).

**rewrites** (list, optional, ``[]``)
  A list of rewrite rules that are applied to incoming requests. Each element of
  the list should be a string value compatible with the format of ``nginx``
  option ``rewrite``. The keyword ``rewrite`` itself should be omitted, as well
  as trailing semi-colon (``;``).

**packages** (list, optional, ``[]``)
  A list of additional packages to install for this particular PHP
  appliction. This is usually going to be different PHP extensions.

**uid** (integer, optional, ``whatever OS picks``)
  UID/GID (they are set-up to be the same) of the dedicated website
  user/group.

**website_mail_recipients** (string, optional, ``root``)
  Space-separated list of e-mails or local users to which the mails, sent to
  either the website admin or website user, should be forwarded to. Forwarding
  is configured via ``~/.forward`` configuration file.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for setting-up two (base) PHP websites (for
running *ownCloud* and *The Bug Genie* applications):

.. code-block:: yaml

    - role: php_website
      fqdn: cloud.example.com
      uid: 2001
      php_file_regex: \.php($|/)
      rewrites:
        - ^/\.well-known/host-meta /public.php?service=host-meta
        - ^/\.well-known/host-meta\.json /public.php?service=host-meta-json
        - ^/\.well-known/carddav /remote.php/carddav/ redirect
        - ^/\.well-known/caldav /remote.php/caldav/ redirect
        - ^/apps/calendar/caldav\.php /remote.php/caldav/
        - ^/apps/contacts/carddav\.php /remote.php/carddav/
        - ^/remote/(.*) /remote.php
      deny_files_regex:
        - ^(\.|autotest|occ|issue|indie|db_|console|build/|tests/|config/|lib/|3rdparty/|templates/).*
      packages:
        # For ownCloud
        - php5-gd
        - php5-json
        - php5-mysql
        - php5-curl
      https_tls_key: "{{ lookup('file', inventory_dir + '/tls/cloud.example.com_https.key') }}"
      https_tls_certificate: "{{ lookup('file', inventory_dir + '/tls/cloud.example.com_https.pem') }}"
      additional_nginx_config:
        - comment: Use custom page for forbidden files.
          value: error_page 403 /core/templates/403.php;
        - comment: Use custom page for non-existing locations/files.
          value: error_page 404 /core/templates/404.php;
      additional_fpm_config:
        "env[PATH]": "\"/usr/local/bin:/usr/bin:/bin\""
      website_mail_recipients: "root john.doe@example.com"
      environment_indicator:
        background_colour: "green"
        text_colour: "black"
        text: "TEST ENVIRONMENT"
    - role: php_website
      deny_files_regex:
        - ^\..*
      php_rewrite_urls:
        - ^(.*) /index.php?url=$1
      fqdn: tbg.example.com
      uid: 2007
      https_tls_key: "{{ lookup('file', inventory_dir + '/tls/tbg.example.com_https.key') }}"
      https_tls_certificate: "{{ lookup('file', inventory_dir + '/tls/tbg.example.com_https.pem') }}"


WSGI Website
------------

The ``wsgi_website`` role can be used for setting-up a website powered by Python
on destination machine. The website needs to use the WSGI specification for
making the Python web application(s) available.

This role is normally not supposed to be used directly, but should instead serve
as the basis for writing website-specific roles. Therefore the role is written
in quite generic way, allowing the integrator to write his/her own logic for
deploying the necessary Python applications/packages, while still reusing a
common base and reducing the workload.

The role implements the following:

* Creates a dedicated user/group for running the WSGI application.
* Creates a dedicated administrator user for maintaining the website.
* Creates a base directory where the website-specific code and data should be
  stored at.
* Adds nginx to website's group, so nginx could read the necessary files.
* Adds website administrator to website's group, so administrator could manage
  the code and data.
* Installs additional packages required for running the role (as configured).
* Sets-up a dedicated Python virtual environment for website.
* Install ``futures`` package in Python virtual environment (required for
  Gunicorn in combination withg Python 2.7).
* Install Gunicorn in Python virtual environment.
* Installs additional packages required for running the role in Python virtual
  environment (as configured).
* Configures systemd to run the website code (using Gunicorn)
* Deploys the HTTPS TLS private key and certificate (for website vhost).
* Configures nginx to serve the website (static files served directly, requests
  passed on to Gunicorn).

The role is implemented with the following layout/logic in mind:

* Website users are named after the ``FQDN`` (fully qualified domain name) of
  website, in format of ``web-ESCAPEDFQDN``, where ``ESCAPEDFQDN`` is equal to
  ``FQDN`` where dots have been replaced by underscores (for example,
  ``web-wiki_example_com``).
* Website users are set-up via GECOS field to have their umask set to ``0007``
  (in combination with ``pam_umask``).
* Administrator users are named after the ``FQDN`` (fully qualified domain name)
  of website, in format of ``admin-ESCAPEDFQDN``, where ``ESCAPEDFQDN`` is equal
  to ``FQDN`` where dots have been replaced by underscores (for example,
  ``admin-cloud_example_com``).
* All websites reside within a dedicated sub-directory in ``/var/www``. The
  sub-directory name is equal to the ``FQDN`` used for accessing the
  website. Owner of the directory is set to be the application administrator,
  while group is set to be the website group. Additionally, ``SGID`` bit is set
  on the directory. This allows admin, with correct umask, to create necessary
  files and directories that should be readable (and eventually writeable) by
  the website user (running the WSGI application) without having to become root.
* All files placed in the website directory should be either created there
  directly, or copied to the directory in order to make sure the ``SGID`` gets
  honored. **Do not move the files, the permissions will not be set correctly.**
* Within the website directory, Python virtual environment can be found within
  the ``virtualenv`` sub-directory. Switching to administrator user via login
  shell will automatically activate the virtual environment.
* Within the website directory, nginx will expect to find the static files
  within the ``htdocs`` sub-directory (this can be symlink too). Locations/aliases
  can be configured for static file serving.
* Within the website directory, systemd service will expect to find the website
  code within the ``code`` sub-directory (this can be symlink too).
* nginx communicates with WSGI server over a dedicated Unix socket for each
  website.


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **common**
* **web_server**


Parameters
~~~~~~~~~~

**additional_nginx_config** (list, optional, ``[]``)
  List providing additional Nginx configuration options to include. This can be
  useful for specifying things like error pages. Options are applied inside of a
  **server** context of Nginx configuration file.

  Each item is a dictionary with the following options describing the extra
  configuration option:

  **comment** (string, mandatory)
    Comment describing the configuration option.

  **value** (string, mandatory)
    Configuration option.

**admin_uid** (integer, optional, ``whatever OS picks``)
  UID of the dedicated website administrator user. The user will be member of
  website group.

**enforce_https** (boolean, optional, ``True``)
  Specify if HTTPS should be enforced for the website or not. If enforced,
  clients connecting via plaintext will be redirected to HTTPS, and clients will
  be served with ``Strict-Transport-Security`` header with value of
  ``max-age=31536000; includeSubDomains``.

**environment_indicator** (dictionary, optional, ``null``)
  Specify configuration for including environment indicator on all HTML
  pages. Indicator is a simple strip at bottom of a page with custom background
  colour, text colour, and text.

  Specifying environment indicator is useful for avoiding mistakes when testing
  by having better visibility what environment you are in
  (production/staging/test).

  The following keys need to be specified:

  **background_colour** (string, mandatory)
    Background colour to use for the strip at bottom. This should be value
    compatible with CSS ``background-color`` attribute.

  **text_colour** (string, mandatory
    Text colour to use for the strip at bottom. This should be value compatible
    with CSS ``color`` attribute.

  **text** (string, mandatory)
    Text to show in show in the strip at bottom.

**environment_variables** (dict, optional, ``{}``)
  Specify additional environment variables that should be set for running the
  service. Environment variables will be set in both the systemd service and for
  the application's administrator user (when logged in as one).

**fqdn** (string, mandatory)
  Fully-qualified domain name where the website is reachable. This value is used
  for calculating the user/group name for dedicated website user, as well as
  home directory of the website user (where data/code should be stored at).

**futures_version** (string, optional, ``3.1.1``)
  Version of ``futures`` package to deploy in virtual environment. Required by
  Gunicorn when using Python 2.7. Default version is tested with the test site.

**gunicorn_version** (string, optional, ``19.7.1``)
  Version of Gunicorn to deploy in virtual environment for running the WSGI
  application. Default version is tested with the test site.

**https_tls_certificate** (string, optional, ``{{ lookup('file', tls_certificate_dir + '/' + fqdn + '_https.pem') }}``)
  X.509 certificate used for TLS for HTTPS service. The file will be stored in
  directory ``/etc/ssl/certs/`` under name ``{{ fqdn }}_https.pem``.

**https_tls_key** (string, optional, ``{{ lookup('file', tls_private_key_dir + '/' + fqdn + '_https.key') }}``)
  Private key used for TLS for HTTPS service. The file will be stored in
  directory ``/etc/ssl/private/`` under name ``{{ fqdn }}_https.key``.

**packages** (list, optional, ``[]``)
  A list of additional packages to install for this particular WSGI
  website. This is usually going to be development libraries for building Python
  packages.

**proxy_headers** (dictionary, optional, ``{}``)
  Additional headers to set when proxying request to Gunicorn. Keys are header
  names, values are header values. Both should be compatible with Nginx
  ``proxy_set_header``. If you need to provide an empty value, use quotes (don't
  forget to surround them by another set of quotes for YAML syntax, for example
  ``"\"\""`` or ``'""'``).

**rewrites** (list, optional, ``[]``)
  A list of rewrite rules that are applied to incoming requests. Each element of
  the list should be a string value compatible with the format of ``nginx``
  option ``rewrite``. The keyword ``rewrite`` itself should be omitted, as well
  as trailing semi-colon (``;``).

**static_locations** (list, optional, ``[]``)
  List of locations that should be treated as static-only, and not processed by
  the WSGI application at all. This is normally used for designating serving of
  static/media files by Nginx (for example, in case of Django projects for
  ``/static/`` and ``/media/``).

**uid** (integer, optional, ``whatever OS picks``)
  UID/GID (they are set-up to be the same) of the dedicated website
  user/group.

**use_paste** (boolean, optional, ``False``)
  Tell Gunicorn to assume that the passed-in ``wsgi_application`` value is a
  filename of a Python Paste ``ini`` file instead of WSGI application.

**virtuaelnv_packages** (list, optional, ``[]``)
  A list of additional packages to install for this particular WSGI appliction
  in its virtual environment using ``pip``.

**website_mail_recipients** (string, optional, ``root``)
  Space-separated list of e-mails or local users to which the mails, sent to
  either the website admin or website user, should be forwarded to. Forwarding
  is configured via ``~/.forward`` configuration file.

**wsgi_application** (string, mandatory)
  WSGI application that should be started by Gunicorn. The format should be
  conformant to what the ``gunicorn`` command-line tool accepts. If the
  ``use_paste`` option is enabled, the value should be equal to filename of the
  Python Paste ini file, located in the ``code`` sub-directory. It should be
  noted that in either case the value should be specsified relative to the
  ``code`` sub-directory. I.e. don't use full paths.

**wsgi_requirements** (list, optional, ``[]``)
  Complete list of pip requirements used for deploying Gunicorn. If specified,
  this list will be used to create requirements file and install Gunicorn and
  its dependencies from that one. This allows to have pinned packages for both
  Gunicorn, futures, and their dependencies.

  It should be noted that this installation method is meant primarily in case of
  roles that want to take advantage of upgrade checks for pip requirements
  files, and that employ `pip-tools <https://github.com/jazzband/pip-tools>`_.

  In addition to change of installation method, when this parameter is specified
  the role will deploy necessary files for running the pip requirements upgrade
  check (see the ``common`` role for description). For this a directory is
  created under ``/etc/pip_check_requirements_upgrades/FQDN``. The same
  directory should be used by dependant roles to deploy their own ``.in`` and
  ``.txt`` files. Make sure the file ownership is set to ``root:pipreqcheck``.

  Should you need to utilise the requirements file in some manner (other than
  checking for its upgrades), it will be also stored (and made accessible to
  application user/admin)) in application's home directory under the name
  ``.wsgi_requirements.txt``.

  To create complete requirements list, it is recommended to use `pip-tools
  <https://github.com/jazzband/pip-tools>`_ (the ``pip-compile`` utility) with
  ``gunicorn`` and ``futures`` in the ``.in.`` file.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for setting-up a (base) WSGI website (for
running a bare Django project):

.. code-block:: yaml

    # Sample for a Django installation.
    - role: wsgi_website
      fqdn: django.example.com
      static_locations:
        - /static
        - /media
      uid: 2004
      virtualenv_packages:
        - django
      wsgi_application: django_example_com.wsgi:application
      environment_variables:
        DJANGO_SETTINGS_MODULE: "django_example_com.settings.production"
      https_tls_key: "{{ lookup('file', inventory_dir + '/tls/wsgi.example.com_https.key') }}"
      https_tls_certificate: "{{ lookup('file', inventory_dir + '/tls/wsgi.example.com_https.pem') }}"
      futures_version: 3.0.5
      gunicorn_version: 19.6.0
      additional_nginx_config:
        - comment: Use custom page for forbidden files.
          value: error_page 403 /static/403.html;
        - comment: Use custom page for non-existing locations/files.
          value: error_page 404 /static/404.html;
      website_mail_recipients: "root john.doe@example.com"
      environment_indicator:
        background_colour: "green"
        text_colour: "black"
        text: "TEST ENVIRONMENT"
      proxy_headers:
        Accept-Encoding: '""'

    # Use wsgi_requirements to deploy Gunicorn.
    - role: wsgi_website
      fqdn: wsgi.example.com
      wsgi_application: wsgi:main
      wsgi_requirements:
        - gunicorn==19.7.1
	- futures==3.1.1


Database Server
---------------

The ``database_server`` role can be used for setting-up a MariaDB database
server on destination machine.

The role implements the following:

* Installs MariaDB server and client.
* Configures MariaDB server and client to use *UTF-8* encoding by default.
* Sets password for the database root user.
* Deploys MariaDB client configuration in location ``/root/.my.cnf`` that
  contains username and password for the root database user.


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **common**


Parameters
~~~~~~~~~~

**db_root_password** (string, mandatory)
  Password for the *root* database user.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for setting-up the database server:

.. code-block:: yaml

   ---

   db_root_password: root


Database
--------

The ``database`` role can be used for creating a MariaDB database and
accompanying user on destination machine.

The role implements the following:

* Creates MariaDB database.
* Creates a dedicated user capable of performing any operation on the created
  database. Username is set to be same as the name of database.
* Sets-up pre-backup task that creates database dump in location
  ``/srv/backup/mariadb/{{ db_name }}.sql``.


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **database_server**
* **backup_client**


Backups
~~~~~~~

If the backup for this role has been enabled, the following paths are backed-up:

**/srv/backup/maraidb/{{ db_name }}.sql**
  Dump of the database. Database dump is created every day at 01:45 in the
  morning.


Parameters
~~~~~~~~~~

**db_name** (string, mandatory)
  Name of the database that should be created.

**db_password** (string, mandatory)
  Password for the database user.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for creating a single database (for some
website):

.. code-block:: yaml

  - role: database
    db_name: phpinfo_example_com
    db_password: phpinfo_example_com


Backup Server
-------------

The ``backup_server`` role can be used for setting-up a server to act as backup
storage for the backup clients. Storage is made available to the clients
exclusively via SFTP on a dedicated port and dedicated OpenSSH server
instance. This instance is specifically configured and tailored for this
purpose.

The role is primarily aimed for use with `Duplicity
<http://duplicity.nongnu.org/>`_, but should be also usable for generic SFTP
uploads.

The role implements the following:

* Installs backup software (Duplicity, Duply).
* Creates a dedicated directory structure for backups with the following structure:

  * ``/srv/backups/`` - main directory under which all the backups reside.
  * ``/srv/backups/SERVER_NAME/`` - home directory for the backup user, name
    after the server. Backup users are confined to their respective home
    directory via chroot. Backup users can't write to their own home directory,
    though.
  * ``/srv/backups/SERVER_NAME/duplicity/`` - directory where the Duplicity
    backups are stored at. This directory is writable by the respective backup
    user.
  * ``SERVER_NAME/.ssh/`` - directory where authorized keys are stored. Backup
    user is not allowed to make modifications to this directory and files
    contained within (i.e. backup users can't add more keys to the
    ``authorized_keys`` file).
* Creates dedicated operating system users for backup clients. These users will
  be made members of the ``backup`` group as well (as an additional group).
* Sets-up ``authorized_keys`` for the backup clients.
* Makes sure the backup users can't log-in via regular OpenSSH server instance.
* Sets-up dedicated OpenSSH server instances to be used exclusively by backup
  clients. The instance listens on TCP port ``2222``.
* Updates firewall to allow incoming TCP connections to port
  ``2222``. Connections are allowed only from the configured IP addresses
  associated with backup clients.


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **common**


Parameters
~~~~~~~~~~

**backup_clients** (list, optional)
  List of backup clients that are connecting to the backup server. This is
  usually done on a per-server basis. Each item in the list is a dictionary
  describing the backup client. The following keys are available:

  **server** (string, mandatory)
    Name of the server that is backed up. It is highly recommended to use
    server's FQDN for this purpose. The dedicated operating system user created
    will have the name of format ``bak-ESCAPED_SERVER_NAME``, where
    ``ESCAPED_SERVER_NAME`` is calculated by taking the passed-in server name
    and replacing all dots (``.``) with undescores (``_``). For example,
    ``web.example.com`` will be turned into ``bak-web_example_com``.

  **uid** (integer, optional, ``whatever OS picks``)
    Uid for the operating system user. User's default group will have a GID
    identical to the user's UID if specified. Otherwise user's default group
    will have OS-determined GID.

  **ip** (IPv4 address, mandatory)
    IPv4 address from which the backup client server is connecting to the backup
    server. Used for introducing stricter firewall rules.

  **public_key** (string, mandatory)
    SSH public key used by backup client to connect to the backup server.

**backup_host_ssh_private_keys** (dictionary, mandatory)
  Defines host keys used for the dedicated OpenSSH server instance for
  backup. Key values that must be provided are: **dsa**, **rsa**, **ed25519**,
  and **ecdsa**, with values for each one of them corresponding to a private key
  generated using the appropriate algorithm. Keys for this purpose can be easily
  created via commands::

    ssh-keygen -f backup_server_dsa_key -N '' -t dsa
    ssh-keygen -f backup_server_rsa_key -N '' -t rsa
    ssh-keygen -f backup_server_ed25519_key -N '' -t ed25519
    ssh-keygen -f backup_server_ecdsa_key -N '' -t ecdsa


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)


Examples
~~~~~~~~

Here is an example configuration for setting-up the backup server role:

.. code-block:: yaml

  - role: backup_server
    backup_clients:
      - server: web.example.com
        uid: 3000
        public_key: "{{ lookup('file', inventory_dir + '/ssh/web.example.com.pub') }}"
        ip: 10.32.64.18
      - server: mail.example.com
        public_key: "{{ lookup('file', inventory_dir + '/ssh/mail.example.com.pub') }}"
        ip: 10.32.64.15
    backup_host_ssh_private_keys:
      dsa: "{{ lookup('file', inventory_dir + '/ssh/backup_server_dsa_key') }}"
      rsa: "{{ lookup('file', inventory_dir + '/ssh/backup_server_rsa_key') }}"
      ed25519: "{{ lookup('file', inventory_dir + '/ssh/backup_server_ed25519_key') }}"
      ecdsa: "{{ lookup('file', inventory_dir + '/ssh/backup_server_ecdsa_key') }}"


Backup Client
-------------

The ``backup_client`` role can be used for setting-up the server as a backup
client so it can perform backups to the backup server.

Backup clients utilise duplicity (via the duply convenience wrapper) for
performing the backups to a backup server via *SFTP* protocol.

The role itself will take care of deploying the necessary software,
configuration files, and encryption/signing private key to the backup client in
order to be able to perform backup.

Files that should be backed-up are specified using the ``backup`` role.

The role implements the following:

* Installs backup software (Duplicity, Duply).
* Sets-up Duply configuration under directory ``/etc/duply/main/``.
* Deploys encryption/signing private key (usually host-specific), as well as
  additional encryption public keys to the server, and imports them into local
  GnuPG keyring used by backup software.
* Deploys private SSH key for logging-in into the backup server over SFTP.
* Deploys ``known_hosts`` file for SFTP fingerprint verification.
* Sets-up a handler that runs scripts/binaries before the actual backup
  run. This is helpful for producing database backups. Such scripts/binaries
  should be deployed to directory ``/etc/duply/main/pre.d/``, and marked
  executable by the root user.

Duply is configured as follows:

* GnuPG keyring is stored under ``/etc/duply/main/gnupg/``. The keyring should
  not be managed manually.
* SSH private key for logging-in into backup server is stored in location
  ``/etc/duply/main/ssh/identity``. Backup server SFTP fingerprint is stored in
  location ``/etc/duply/main/ssh/known_hosts``.
* Base directory for back-ups is root (``/``), but *all* files are excluded by
  default to prevent huge back-ups. Ansible roles that want to utilise the
  backup client role can specify which patterns should be included in the backup
  when including the ``backup`` role. Include pattern file is assembled and
  stored in location ``/etc/duply/main/include``.
* Backups are encrypted and signed with the specified encryption key.
* Maximum age for old backups is set to 6 months.
* Maximum age for full backups is set to 1 month.
* Volume size is set to 1GB.
* Pre-backup scripts are run via ``/etc/duply/main/pre`` handler that tries to
  execute scripts/binaries from directory ``/etc/duply/main/pre.d/``.

.. note::
   Since at time of this writing there are no lookup plugins for extracting key
   material/information from GnuPG keyring, you may want to resort to extraction
   of keys on the controller machine via lookups similar to::

     lookup('pipe', 'gpg2 --homedir /path/to/your/keyring --armor --export some_identifier')
     lookup('pipe', 'gpg2 --homedir /path/to/your/keyring --armor --export-secret-keys some_identifier')

   This may not be the most elegant solution, but for now it offers better
   flexibility (theoretically, you could store all those keys etc as plaintext
   files instead).


Parameters
~~~~~~~~~~

**backup_additional_encryption_keys** (list, optional, ``[]``)
  List of additional public encryption keys used for backup operation. Each item
  in the list should be an ASCII armour-encoded public key exported from a GnuPG
  keyring. These additional public keys are useful in cases where the backups
  should be decryptable with some master key in addition to server-specific key.

**backup_client_username** (string, optional, ``bak-{{ ansible_fqdn | replace('.', '_') }}``)
  Username for connecting to the backup server via SFTP.

**backup_encryption_key** (string, mandatory)
  Private GnuPG key, encoded using ASCII armor, used for encryption and signing
  operations when running the backup on the client server. This *must* be a
  private key! This is normally host-specific encryption key that is distributed
  to destination server and that can be also used for the restore operations
  (for data decryption). The key must not be password-protected.

**backup_server** (string, mandatory)
  Backup server to connect to.

**backup_server_destination** (string, optional, ``//duplicity``)
  Target directory on the backup server where the backups are stored.

**backup_server_host_ssh_public_keys** (list, mandatory)
  SSH public keys presented by the server during client authentication. These
  public keys are used for populating the known hosts on the backup client side
  for host verification purposes.

**backup_server_port** (int, optional, ``2222``)
  Port on the backup server to connect to for accessing the SFTP service.

**backup_ssh_key** (string, mandatory)
  SSH private key for logging-in into the backup server.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)
- Debian 9 (Stretch)


Examples
~~~~~~~~

Here is an example configuration for setting-up the role (take note that lookup
plugin is quite useful here for fetching key values from some local directory):

.. code-block:: yaml

  - role: backup_client
    backup_additional_encryption_keys: "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
    backup_client_username: "user"
    backup_encryption_key: "-----BEGIN PGP PRIVATE KEY BLOCK-----\n...\n-----END PGP PRIVATE KEY BLOCK-----"
    backup_server: "backup.example.com"
    backup_server_destination: "//example/host"
    backup_server_host_ssh_public_keys:
      - "{{ lookup('file', inventory_dir + '/ssh/backup_server_dsa_key.pub') }}"
      - "{{ lookup('file', inventory_dir + '/ssh/backup_server_ecdsa_key.pub') }}"
      - "{{ lookup('file', inventory_dir + '/ssh/backup_server_ed25519_key.pub') }}"
      - "{{ lookup('file', inventory_dir + '/ssh/backup_server_rsa_key.pub') }}"
    backup_server_port: 22
    backup_ssh_key: "{{ lookup('file', inventory_dir + '/ssh/web.example.com') }}"


Backup
------

The ``backup`` role can be used to specify what files should be backed-up to the
backup server.

The role provides a convenient way to deploy a file containing file and
directory patterns describing the file/directory paths that should be included
in the back-up.

The role implements the following:

* Installs a file with provided patterns in directory
  ``/etc/duply/main/patterns/``.
* Assembles/refresshes the main include pattern file at
  ``/etc/duply/main/include``.


Role dependencies
~~~~~~~~~~~~~~~~~

Depends on the following roles:

* **backup_client**


Parameters
~~~~~~~~~~

**backup_patterns_filename** (string, mandatory)
  Name of the backup patterns file. The file is stored in directory
  ``/etc/duply/main/patterns/``. This should be a unique filename amongst all
  roles. If role can be included multiple times, make sure the filename is
  always unique when depending on the backup role.

**backup_patterns** (list, optional, ``[]``)
  List of globbing patterns defining which files or directories should be
  backed-up.


Distribution compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~

Role is compatible with the following distributions:

- Debian 8 (Jessie)
- Debian 9 (Stretch)


Examples
~~~~~~~~

Here is an example configuration for setting-up the role:

.. code-block:: yaml

  - role: backup
    backup_patterns_filename: myapp
    backup_patters:
      - /var/www/myapp.example.com