Skip to content

Commit 8b63fa0

Browse files
committed
Merge remote-tracking branch 'origin/master' into edge
2 parents cd246e7 + 2fdbe02 commit 8b63fa0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+9568
-43
lines changed

mig/install/generateconfs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,8 @@ def usage(options):
355355
if val == 'DEFAULT':
356356
del settings[key]
357357
conf = generate_confs(**settings)
358-
# print "DEBUG: %s" % conf
359-
instructions_path = "%(destination)s/instructions.txt" % conf
358+
# TODO: avoid reconstructing this path (also done inside generate_confs)
359+
instructions_path = "%s/instructions.txt" % conf['destination_path']
360360
try:
361361
instructions_fd = open(instructions_path, "r")
362362
instructions = instructions_fd.read()

mig/shared/defaults.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import os
3333
import sys
3434

35+
MIG_BASE = os.path.realpath(os.path.join(os.path.dirname(__file__), '../..'))
3536
MIG_ENV = os.getenv('MIG_ENV', 'default')
3637

3738
# NOTE: python3 switched strings to use unicode by default in contrast to bytes
@@ -76,6 +77,31 @@
7677
any_protocol = keyword_any
7778
any_state = keyword_any
7879

80+
mig_user = {
81+
'default': 'mig',
82+
'local': keyword_auto,
83+
}[MIG_ENV]
84+
85+
mig_group = {
86+
'default': 'mig',
87+
'local': keyword_auto,
88+
}[MIG_ENV]
89+
90+
default_source = {
91+
'default': keyword_auto,
92+
'local': os.path.join(MIG_BASE, "mig/install"),
93+
}[MIG_ENV]
94+
95+
default_destination = {
96+
'default': keyword_auto,
97+
'local': os.path.join(MIG_BASE, "envhelp/output/confs"),
98+
}[MIG_ENV]
99+
100+
default_enable_events = {
101+
'default': True,
102+
'local': False
103+
}[MIG_ENV]
104+
79105
AUTH_NONE, AUTH_GENERIC, AUTH_CERTIFICATE = "None", "Generic", "X.509 Certificate"
80106
AUTH_OPENID_CONNECT, AUTH_OPENID_V2 = "OpenID Connect", "OpenID 2.0"
81107

mig/shared/install.py

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import base64
4141
import crypt
4242
import datetime
43+
import grp
4344
import os
4445
import pwd
4546
import random
@@ -49,11 +50,13 @@
4950
import sys
5051

5152
from mig.shared.defaults import default_http_port, default_https_port, \
53+
mig_user, mig_group, default_source, default_destination, \
5254
auth_openid_mig_db, auth_openid_ext_db, STRONG_TLS_CIPHERS, \
5355
STRONG_TLS_CURVES, STRONG_SSH_KEXALGOS, STRONG_SSH_LEGACY_KEXALGOS, \
5456
STRONG_SSH_CIPHERS, STRONG_SSH_LEGACY_CIPHERS, STRONG_SSH_MACS, \
5557
STRONG_SSH_LEGACY_MACS, CRACK_USERNAME_REGEX, CRACK_WEB_REGEX, \
5658
keyword_any, keyword_auto
59+
from mig.shared.compat import ensure_native_string
5760
from mig.shared.fileio import read_file, read_file_lines, write_file, \
5861
write_file_lines
5962
from mig.shared.htmlgen import menu_items
@@ -187,8 +190,8 @@ def template_remove(template_file, remove_pattern):
187190
def generate_confs(
188191
# NOTE: make sure command line args with white-space are properly wrapped
189192
generateconfs_command=subprocess.list2cmdline(sys.argv),
190-
source=os.path.dirname(sys.argv[0]),
191-
destination=os.path.dirname(sys.argv[0]),
193+
source=default_source,
194+
destination=default_destination,
192195
destination_suffix="",
193196
base_fqdn='',
194197
public_fqdn='',
@@ -217,8 +220,9 @@ def generate_confs(
217220
jupyter_services_desc='{}',
218221
cloud_services='',
219222
cloud_services_desc='{}',
220-
user='mig',
221-
group='mig',
223+
user=mig_user,
224+
group=mig_group,
225+
timezone=keyword_auto,
222226
apache_version='2.4',
223227
apache_etc='/etc/apache2',
224228
apache_run='/var/run',
@@ -358,6 +362,8 @@ def generate_confs(
358362
openid_port=8443,
359363
openid_show_port='',
360364
openid_session_lifetime=43200,
365+
seafile_secret=keyword_auto,
366+
seafile_ccnetid=keyword_auto,
361367
seafile_seahub_port=8000,
362368
seafile_seafhttp_port=8082,
363369
seafile_client_port=13419,
@@ -403,12 +409,31 @@ def generate_confs(
403409
quota_backend='lustre',
404410
quota_user_limit=(1024**4),
405411
quota_vgrid_limit=(1024**4),
412+
_getpwnam=pwd.getpwnam,
406413
):
407414
"""Generate Apache and MiG server confs with specified variables"""
408415

409416
# Read out dictionary of args with defaults and overrides
410417

411-
expanded = locals()
418+
expanded = dict(locals())
419+
420+
# expand any directory path specific as "auto" relative to CWD
421+
if source is keyword_auto:
422+
expanded['source'] = os.path.dirname(sys.argv[0])
423+
source = expanded['source']
424+
if destination is keyword_auto:
425+
expanded['destination'] = os.path.dirname(sys.argv[0])
426+
destination = expanded['destination']
427+
428+
# expand any user information marked as "auto" based on the environment
429+
if user is keyword_auto:
430+
user = pwd.getpwuid(os.getuid())[0]
431+
if group is keyword_auto:
432+
group = grp.getgrgid(os.getgid())[0]
433+
434+
# finalize a destination path up-front
435+
expanded['destination_path'] = "%s%s" % (destination, destination_suffix)
436+
destination_path = expanded['destination_path']
412437

413438
# Backwards compatibility with old name
414439
if public_port and not public_http_port:
@@ -656,7 +681,7 @@ def generate_confs(
656681
user_dict['__QUOTA_VGRID_LIMIT__'] = "%s" % quota_vgrid_limit
657682

658683
# Needed for PAM/NSS
659-
pw_info = pwd.getpwnam(user)
684+
pw_info = _getpwnam(user)
660685
user_dict['__MIG_UID__'] = "%s" % (pw_info.pw_uid)
661686
user_dict['__MIG_GID__'] = "%s" % (pw_info.pw_gid)
662687

@@ -916,22 +941,36 @@ def generate_confs(
916941
prio_duplicati_protocols.append('davs')
917942
user_dict['__DUPLICATI_PROTOCOLS__'] = ' '.join(prio_duplicati_protocols)
918943

919-
sys_timezone = 'UTC'
920-
timezone_cmd = ["/usr/bin/timedatectl", "status"]
921-
try:
922-
timezone_proc = subprocess_popen(timezone_cmd, stdout=subprocess_pipe)
923-
for line in timezone_proc.stdout.readlines():
924-
line = line.strip()
925-
if not line.startswith("Time zone: "):
926-
continue
927-
sys_timezone = line.replace("Time zone: ", "").split(" ", 1)[0]
928-
except Exception as exc:
929-
print("WARNING: failed to extract system time zone: %s" % exc)
930-
user_dict['__SEAFILE_TIMEZONE__'] = sys_timezone
931-
user_dict['__SEAFILE_SECRET_KEY__'] = base64.b64encode(
932-
os.urandom(32)).lower()
933-
user_dict['__SEAFILE_CCNET_ID__'] = base64.b16encode(
934-
os.urandom(20)).lower()
944+
if timezone is keyword_auto:
945+
# attempt to detect the timezone
946+
sys_timezone = None
947+
try:
948+
timezone_cmd = ["/usr/bin/timedatectl", "status"]
949+
timezone_proc = subprocess_popen(timezone_cmd, stdout=subprocess_pipe)
950+
for line in timezone_proc.stdout.readlines():
951+
line = ensure_native_string(line.strip())
952+
if not line.startswith("Time zone: "):
953+
continue
954+
sys_timezone = line.replace("Time zone: ", "").split(" ", 1)[0]
955+
except OSError as exc:
956+
# warn about any issues executing the command but continue
957+
pass
958+
if sys_timezone is None:
959+
print("WARNING: failed to extract system time zone; defaulting to UTC")
960+
sys_timezone = 'UTC'
961+
962+
timezone = sys_timezone
963+
964+
user_dict['__SEAFILE_TIMEZONE__'] = timezone
965+
966+
if seafile_secret is keyword_auto:
967+
seafile_secret = ensure_native_string(base64.b64encode(os.urandom(32))).lower()
968+
user_dict['__SEAFILE_SECRET_KEY__'] = seafile_secret
969+
970+
if seafile_ccnetid is keyword_auto:
971+
seafile_ccnetid = ensure_native_string(base64.b64encode(os.urandom(20))).lower()
972+
user_dict['__SEAFILE_CCNET_ID__'] = seafile_ccnetid
973+
935974
user_dict['__SEAFILE_SHORT_NAME__'] = short_title.replace(' ', '-')
936975
# IMPORTANT: we discriminate on local and remote seafile service
937976
# for local ones we partly integrate directly with apache etc.
@@ -1584,14 +1623,16 @@ def generate_confs(
15841623
user_dict['__ALL_OIDC_PROVIDER_META_URLS__'] = ' '.join(
15851624
all_oidc_provider_meta_urls)
15861625

1587-
destination_path = "%s%s" % (destination, destination_suffix)
15881626
if not os.path.islink(destination) and os.path.isdir(destination):
15891627
print("ERROR: Legacy %s dir in the way - please remove first" %
15901628
destination)
15911629
sys.exit(1)
15921630
try:
15931631
os.makedirs(destination_path)
1594-
if os.path.exists(destination):
1632+
except OSError:
1633+
pass
1634+
try:
1635+
if os.path.lexists(destination):
15951636
os.remove(destination)
15961637
os.symlink(destination_path, destination)
15971638
except OSError:
@@ -1691,16 +1732,17 @@ def generate_confs(
16911732
default_https_port])
16921733
user_dict['__SID_URL__'] += ':%(__SID_PORT__)s' % user_dict
16931734

1694-
if digest_salt == keyword_auto:
1735+
if digest_salt is keyword_auto:
16951736
# Generate random hex salt for scrambling saved digest credentials
1696-
digest_salt = base64.b16encode(os.urandom(16))
1697-
if crypto_salt == keyword_auto:
1698-
# Generate random hex salt for various crypto helpers
1699-
crypto_salt = base64.b16encode(os.urandom(16))
1700-
1737+
digest_salt = ensure_native_string(base64.b16encode(os.urandom(16)))
17011738
user_dict['__DIGEST_SALT__'] = digest_salt
1739+
1740+
if crypto_salt is keyword_auto:
1741+
# Generate random hex salt for various crypto helpers
1742+
crypto_salt = ensure_native_string(base64.b16encode(os.urandom(16)))
17021743
user_dict['__CRYPTO_SALT__'] = crypto_salt
17031744

1745+
17041746
# Greedy match trailing space for all the values to uncomment stuff
17051747
strip_trailing_space = ['__IF_SEPARATE_PORTS__', '__APACHE_PRE2.4__',
17061748
'__APACHE_RECENT__']
@@ -1989,7 +2031,7 @@ def generate_confs(
19892031
sudo cp %(destination)s/migacctexpire /etc/cron.monthly/
19902032
19912033
''' % expanded
1992-
instructions_path = "%s/instructions.txt" % destination
2034+
instructions_path = "%s/instructions.txt" % destination_path
19932035
if not write_file(instructions, instructions_path, None):
19942036
print("could not write instructions ot %s" % instructions_path)
19952037
return expanded

recommended.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ requests
1414
#cracklib
1515
pdfkit
1616
xvfbwrapper
17-
pyotp
1817
openstackclient
1918
pyyaml
2019
nbformat

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# migrid dependencies on a format suitable for pip install as described on
22
# https://pip.pypa.io/en/stable/reference/requirement-specifiers/
33
future
4+
pyotp;python_version >= "3"
5+
pyotp<2.4;python_version < "3"
46
pyyaml
57

68
# NOTE: additional optional dependencies depending on site conf are listed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Custom MiG network daemon filter to detect attempts to brute-force guess user passwords
2+
# and common scanning bots
3+
4+
[DEFAULT]
5+
normal = ^.* WARNING IP: <HOST>, Protocol: .+, Type: .+, Username: .+, Message: Exceeded rate limit$
6+
7+
# Authlog handles password crack detection
8+
pw_crack = ^.* CRITICAL IP: <HOST>, Protocol: .+, Type: .+, Username: .+, Message: (Crack username detected|Abuse limit reached)$
9+
10+
# Repeated native sftp handshake errors from weak client security indicate a scan bot
11+
handshake = ^.* WARNING client negotiation errors for \('<HOST>', [0-9]+\): (Incompatible ssh (peer|server) \(no acceptable (kex algorithm|ciphers|macs|host key)\))?$
12+
13+
# Common web vulnerability scans are a clear sign of malice
14+
webscan = ^.* ERROR got path from <HOST> with invalid root: /home/mig/state/webserver_home/((HNAP1|GponForm|provisioning|provision|prov|polycom|yealink|CertProv|phpmyadmin|admin|cfg|wp|wordpress|cms|blog|old|new|test|dev|tmp|temp|remote|mgmt|properties|authenticate|tmui|ddem|a2billing|vtigercrm|secure|rpc|recordings|dana-na)(/.*|)|.*(Login|login|logon|configuration|header|admin|index)\.(php|jsp|asp)|(api/v1/pods|Telerik.Web.UI.WebResource.axd))$
15+
16+
17+
[INCLUDES]
18+
before = common.conf
19+
20+
[Definition]
21+
failregex = %(normal)s
22+
#ignoreregex =
23+
24+
[Init]
25+
maxlines = 1
26+
# Use pyinotify or poll on native log file rather than systemd journal
27+
#journalmatch = _SYSTEMD_UNIT=migrid.service + _COMM=grid_webdavs.py
28+
journalmatch =
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Custom MiG network daemon filter to detect and ban repeated handshake errors common for bots
2+
3+
[INCLUDES]
4+
before = MiG-daemons.conf
5+
6+
[Definition]
7+
failregex = %(handshake)s

0 commit comments

Comments
 (0)