Skip to content

Commit 2fdbe02

Browse files
committed
manually merge PR72 with minor adjustments. Added missing license header, adjusted long comment to fit line, removed pyoth from recommended.txt now that it's in required.txt and fix a couple of typos in comment.
git-svn-id: svn+ssh://svn.code.sf.net/p/migrid/code/trunk@6069 b75ad72c-e7d7-11dd-a971-7dbc132099af
1 parent b1d70f6 commit 2fdbe02

Some content is hidden

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

50 files changed

+9567
-42
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)