Merge "Bring in ovs_config module/state"
diff --git a/.gitignore b/.gitignore
index aa8e42a..cc3ab8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,8 @@
.kitchen
+.bundle
+bundle/
tests/build/
*.swp
*.pyc
.ropeproject
+Gemfile*
diff --git a/.travis.yml b/.travis.yml
index 78246a5..fac2153 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,6 @@
+language: python
+python:
+- "2.7.13"
sudo: required
services:
- docker
diff --git a/README.rst b/README.rst
index 986ec72..f35bce7 100644
--- a/README.rst
+++ b/README.rst
@@ -70,6 +70,30 @@
home: '/home/elizabeth'
password: "$6$nUI7QEz3$dFYjzQqK5cJ6HQ38KqG4gTWA9eJu3aKx6TRVDFh6BVJxJgFWg2akfAA7f1fCxcSUeOJ2arCO6EEI6XXnHXxG10"
+Configure password expiration parameters
+----------------------------------------
+The following login.defs parameters can be overridden per-user:
+
+* PASS_MAX_DAYS
+* PASS_MIN_DAYS
+* PASS_WARN_DAYS
+* INACTIVE
+
+.. code-block:: yaml
+
+ linux:
+ system:
+ ...
+ user:
+ jdoe:
+ name: 'jdoe'
+ enabled: true
+ ...
+ maxdays: <PASS_MAX_DAYS>
+ mindays: <PASS_MIN_DAYS>
+ warndays: <PASS_WARN_DAYS>
+ inactdays: <INACTIVE>
+
Configure sudo for users and groups under ``/etc/sudoers.d/``.
This ways ``linux.system.sudo`` pillar map to actual sudo attributes:
@@ -235,7 +259,54 @@
automatic_reboot: true
automatic_reboot_time: "02:00"
-Linux with cron jobs
+Managing cron tasks
+-------------------
+
+There are two data structures that are related to managing cron itself and
+cron tasks:
+
+.. code-block:: yaml
+
+ linux:
+ system:
+ cron:
+
+and
+
+.. code-block:: yaml
+
+ linux:
+ system:
+ job:
+
+`linux:system:cron` manages cron packages, services, and '/etc/cron.allow' file.
+
+'deny' files are managed the only way - we're ensuring they are absent, that's
+a requirement from CIS 5.1.8
+
+'cron' pillar structure is the following:
+
+.. code-block:: yaml
+
+ linux:
+ system:
+ cron:
+ enabled: true
+ pkgs: [ <cron packages> ]
+ services: [ <cron services> ]
+ user:
+ <username>:
+ enabled: true
+
+To add user to '/etc/cron.allow' use 'enabled' key as shown above.
+
+'/etc/cron.deny' is not managed as CIS 5.1.8 requires it was removed.
+
+A user would be ignored if any of the following is true:
+* user is disabled in `linux:system:user:<username>`
+* user is disabled in `linux:system:cron:user:<username>`
+
+`linux:system:job` manages individual cron tasks.
By default, it will use name as an identifier, unless identifier key is
explicitly set or False (then it will use Salt's default behavior which is
@@ -255,6 +326,32 @@
hour: 2
minute: 0
+Managing 'at' tasks
+-------------------
+
+Pillar for managing `at` tasks is similar to one for `cron` tasks:
+
+.. code-block:: yaml
+
+ linux:
+ system:
+ at:
+ enabled: true
+ pkgs: [ <at packages> ]
+ services: [ <at services> ]
+ user:
+ <username>:
+ enabled: true
+
+To add a user to '/etc/at.allow' use 'enabled' key as shown above.
+
+'/etc/at.deny' is not managed as CIS 5.1.8 requires it was removed.
+
+A user will be ignored if any of the following is true:
+* user is disabled in `linux:system:user:<username>`
+* user is disabled in `linux:system:at:user:<username>`
+
+
Linux security limits (limit sensu user memory usage to max 1GB):
.. code-block:: yaml
@@ -732,6 +829,22 @@
power/state: "root:power"
- devices/system/cpu/cpu0/cpufreq/scaling_governor: powersave
+Sysfs definition with disabled automatic write. Attributes are saved
+to configuration, but are not applied during the run.
+Thay will be applied automatically after the reboot.
+
+
+.. code-block:: yaml
+
+ linux:
+ system:
+ sysfs:
+ enable_apply: false
+ scheduler:
+ block/sda/queue/scheduler: deadline
+
+.. note:: The `enable_apply` parameter defaults to `True` if not defined.
+
Huge Pages
~~~~~~~~~~~~
@@ -829,6 +942,31 @@
priority: 900
package: '*'
+If you need to add multiple pin rules for one repo, please use new,ordered definition format
+('pinning' definition will be in priotity to use):
+
+.. code-block:: yaml
+
+ linux:
+ system:
+ repo:
+ mcp_saltstack:
+ source: "deb [arch=amd64] http://repo.saltstack.com/apt/ubuntu/16.04/amd64/2017.7/ xenial main"
+ architectures: amd64
+ clean_file: true
+ pinning:
+ 10:
+ enabled: true
+ pin: 'release o=SaltStack'
+ priority: 50
+ package: 'libsodium18'
+ 20:
+ enabled: true
+ pin: 'release o=SaltStack'
+ priority: 1100
+ package: '*'
+
+
.. note:: For old Ubuntu releases (<xenial)
extra packages for apt transport, like ``apt-transport-https``
may be required to be installed manually.
@@ -1556,6 +1694,23 @@
export FTP_PROXY=ftp://127.0.3.3:2121
export NO_PROXY='.local'
+
+Configure login.defs parameters
+-------------------------------
+
+.. code-block:: yaml
+
+ linux:
+ system:
+ login_defs:
+ <opt_name>:
+ enabled: true
+ value: <opt_value>
+
+<opt_name> is a configurational option defined in 'man login.defs'.
+<opt_name> is case sensitive, should be UPPERCASE only!
+
+
Linux with hosts
Parameter ``purge_hosts`` will enforce whole ``/etc/hosts file``,
@@ -2080,6 +2235,240 @@
interface: bond0
mac: "ff:ff:ff:ff:ff:ff" (optional)
+Check network params on the environment
+---------------------------------------
+
+Grab nics and nics states
+
+.. code-block:: bash
+
+ salt osd001\* net_checks.get_nics
+
+**Example of system output:**
+
+.. code-block:: bash
+
+ osd001.domain.com:
+ |_
+ - bond0
+ - None
+ - 1e:c8:64:42:23:b9
+ - 0
+ - 1500
+ |_
+ - bond1
+ - None
+ - 3c:fd:fe:27:3b:00
+ - 1
+ - 9100
+ |_
+ - fourty1
+ - None
+ - 3c:fd:fe:27:3b:00
+ - 1
+ - 9100
+ |_
+ - fourty2
+ - None
+ - 3c:fd:fe:27:3b:02
+ - 1
+ - 9100
+
+Grab 10G nics PCI addresses for hugepages setup
+
+.. code-block:: bash
+
+ salt cmp001\* net_checks.get_ten_pci
+
+**Example of system output:**
+
+.. code-block:: bash
+
+ cmp001.domain.com:
+ |_
+ - ten1
+ - 0000:19:00.0
+ |_
+ - ten2
+ - 0000:19:00.1
+ |_
+ - ten3
+ - 0000:19:00.2
+ |_
+ - ten4
+ - 0000:19:00.3
+
+Grab ip address for an interface
+
+.. code-block:: bash
+
+ salt cmp001\* net_checks.get_ip iface=one4
+
+**Example of system output:**
+
+.. code-block:: bash
+
+ cmp001.domain.com:
+ 10.200.177.101
+
+Grab ip addresses map
+
+.. code-block:: bash
+
+ salt-call net_checks.nodes_addresses
+
+**Example of system output:**
+
+.. code-block:: bash
+
+ local:
+ |_
+ - cid01.domain.com
+ |_
+ |_
+ - pxe
+ - 10.200.177.91
+ |_
+ - control
+ - 10.200.178.91
+ |_
+ - cmn02.domain.com
+ |_
+ |_
+ - storage_access
+ - 10.200.181.67
+ |_
+ - pxe
+ - 10.200.177.67
+ |_
+ - control
+ - 10.200.178.67
+ |_
+ - cmp010.domain.com
+ |_
+ |_
+ - pxe
+ - 10.200.177.110
+ |_
+ - storage_access
+ - 10.200.181.110
+ |_
+ - control
+ - 10.200.178.110
+ |_
+ - vxlan
+ - 10.200.179.110
+
+Verify full mesh connectivity
+
+.. code-block:: bash
+
+ salt-call net_checks.ping_check
+
+**Example of positive system output:**
+
+.. code-block:: bash
+
+ ['PASSED']
+ [INFO ] ['PASSED']
+ local:
+ True
+
+**Example of system output in case of failure:**
+
+.. code-block:: bash
+
+ FAILED
+ [ERROR ] FAILED
+ ['control: 10.0.1.92 -> 10.0.1.224: Failed']
+ ['control: 10.0.1.93 -> 10.0.1.224: Failed']
+ ['control: 10.0.1.51 -> 10.0.1.224: Failed']
+ ['control: 10.0.1.102 -> 10.0.1.224: Failed']
+ ['control: 10.0.1.13 -> 10.0.1.224: Failed']
+ ['control: 10.0.1.81 -> 10.0.1.224: Failed']
+ local:
+ False
+
+For this feature to work, please mark addresses with some role.
+Otherwise 'default' role is assumed and mesh would consist of all
+addresses on the environment.
+
+Mesh mark is needed only for interfaces which are enabled and have
+ip address assigned.
+
+Checking dhcp pxe network meaningless, as it is used for salt
+master vs minion communications, therefore treated as checked.
+
+.. code-block:: yaml
+
+ parameters:
+ linux:
+ network:
+ interface:
+ ens3:
+ enabled: true
+ type: eth
+ proto: static
+ address: ${_param:deploy_address}
+ netmask: ${_param:deploy_network_netmask}
+ gateway: ${_param:deploy_network_gateway}
+ mesh: pxe
+
+Check pillars for ip address duplicates
+
+.. code-block:: bash
+
+ salt-call net_checks.verify_addresses
+
+**Example of positive system output:**
+
+.. code-block:: bash
+
+ ['PASSED']
+ [INFO ] ['PASSED']
+ local:
+ True
+
+**Example of system output in case of failure:**
+
+.. code-block:: bash
+
+ FAILED. Duplicates found
+ [ERROR ] FAILED. Duplicates found
+ ['gtw01.domain.com', 'gtw02.domain.com', '10.0.1.224']
+ [ERROR ] ['gtw01.domain.com', 'gtw02.domain.com', '10.0.1.224']
+ local:
+ False
+
+Generate csv report for the env
+
+.. code-block:: bash
+
+ salt -C 'kvm* or cmp* or osd*' net_checks.get_nics_csv \
+ | grep '^\ ' | sed 's/\ *//g' | grep -Ev ^server \
+ | sed '1 i\server,nic_name,ip_addr,mac_addr,link,mtu,chassis_id,chassis_name,port_mac,port_descr'
+
+**Example of system output:**
+
+.. code-block:: bash
+
+ server,nic_name,ip_addr,mac_addr,link,mtu,chassis_id,chassis_name,port_mac,port_descr
+ cmp010.domain.com,bond0,None,b4:96:91:10:5b:3a,1,1500,,,,
+ cmp010.domain.com,bond0.21,10.200.178.110,b4:96:91:10:5b:3a,1,1500,,,,
+ cmp010.domain.com,bond0.22,10.200.179.110,b4:96:91:10:5b:3a,1,1500,,,,
+ cmp010.domain.com,bond1,None,3c:fd:fe:34:ad:22,0,1500,,,,
+ cmp010.domain.com,bond1.24,10.200.181.110,3c:fd:fe:34:ad:22,0,1500,,,,
+ cmp010.domain.com,fourty5,None,3c:fd:fe:34:ad:20,0,9000,,,,
+ cmp010.domain.com,fourty6,None,3c:fd:fe:34:ad:22,0,9000,,,,
+ cmp010.domain.com,one1,None,b4:96:91:10:5b:38,0,1500,,,,
+ cmp010.domain.com,one2,None,b4:96:91:10:5b:39,1,1500,f0:4b:3a:8f:75:40,exnfvaa18-20,548,ge-0/0/22
+ cmp010.domain.com,one3,None,b4:96:91:10:5b:3a,1,1500,f0:4b:3a:8f:75:40,exnfvaa18-20,547,ge-0/0/21
+ cmp010.domain.com,one4,10.200.177.110,b4:96:91:10:5b:3b,1,1500,f0:4b:3a:8f:75:40,exnfvaa18-20,546,ge-0/0/20
+ cmp011.domain.com,bond0,None,b4:96:91:13:6c:aa,1,1500,,,,
+ cmp011.domain.com,bond0.21,10.200.178.111,b4:96:91:13:6c:aa,1,1500,,,,
+ cmp011.domain.com,bond0.22,10.200.179.111,b4:96:91:13:6c:aa,1,1500,,,,
+ ...
+
Usage
=====
diff --git a/_modules/net_checks.py b/_modules/net_checks.py
new file mode 100644
index 0000000..cb0f4fc
--- /dev/null
+++ b/_modules/net_checks.py
@@ -0,0 +1,279 @@
+from os import listdir, path
+from subprocess import Popen,PIPE
+from re import findall as refindall
+from re import search as research
+import salt.utils
+import socket, struct, fcntl
+import logging
+
+logger = logging.getLogger(__name__)
+stream = logging.StreamHandler()
+logger.addHandler(stream)
+
+def get_ip(iface='ens2'):
+
+ ''' Get ip address from an interface if applicable
+
+ :param iface: Interface name. Type: str
+
+ '''
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sockfd = sock.fileno()
+ SIOCGIFADDR = 0x8915
+ ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
+
+ try:
+ res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
+ except:
+ logger.debug("No ip addresses assigned to %s" % iface)
+ return None
+
+ ip = struct.unpack('16sH2x4s8x', res)[2]
+ return socket.inet_ntoa(ip)
+
+def get_nics():
+
+ ''' List nics '''
+
+ nics = []
+ nics_list = listdir('/sys/class/net/')
+ for nic_name in nics_list:
+ if research('(br|bond|ens|enp|eth|one|ten|fourty)[0-9]+', nic_name):
+
+ # Interface should be in "up" state in order to get carrier status
+ Popen("ip li set dev " + nic_name + " up", shell=True, stdout=PIPE)
+
+ with open("/sys/class/net/" + nic_name + "/carrier", 'r') as f:
+ try:
+ carrier = int(f.read())
+ except:
+ carrier = 0
+
+ bond = ""
+ if path.isfile("/sys/class/net/" + nic_name + "/master/uevent"):
+ with open("/sys/class/net/" + nic_name + "/master/uevent", 'r') as f:
+ for line in f:
+ sline = line.strip()
+ if 'INTERFACE=bond' in sline:
+ bond = sline.split('=')[1]
+ if len(bond) == 0:
+ with open("/sys/class/net/" + nic_name + "/address", 'r') as f:
+ macaddr = f.read().strip()
+ else:
+ with open("/proc/net/bonding/" + bond, 'r') as f:
+ line = f.readline()
+ if_struct = False
+ while line:
+ sline = line.strip()
+ if 'Slave Interface: ' + nic_name in sline and not if_struct:
+ if_struct = True
+ if 'Permanent HW addr: ' in sline and if_struct:
+ macaddr = sline.split()[3]
+ break
+ line = f.readline()
+
+ with open("/sys/class/net/" + nic_name + "/mtu", 'r') as f:
+ mtu = f.read()
+
+ ip = str(get_ip(nic_name))
+
+ nics.append([nic_name, ip, macaddr, carrier, mtu])
+
+ return sorted(nics)
+
+def get_ten_pci():
+
+ ''' List ten nics pci addresses '''
+
+ nics = []
+ nics_list = listdir('/sys/class/net/')
+ for nic_name in nics_list:
+ if research('ten[0-9]+', nic_name):
+ with open("/sys/class/net/" + nic_name + "/device/uevent", 'r') as f:
+ for line in f:
+ sline = line.strip()
+ if "PCI_SLOT_NAME=" in sline:
+ nics.append([nic_name , sline.split("=")[1]])
+
+ return sorted(nics)
+
+def mesh_ping(mesh):
+
+ ''' One to many ICMP check
+
+ :param hosts: Target hosts. Type: list of ip addresses
+
+ '''
+
+ io = []
+ minion_id = __salt__['config.get']('id')
+
+ for host, hostobj in mesh:
+ if host == minion_id:
+ for mesh_net, addr, targets in hostobj:
+ if addr in targets:
+ targets.remove(addr)
+ for tgt in targets:
+ # This one will run in parallel with everyone else
+ worker = Popen("ping -c 1 -w 1 -W 1 " + str(tgt), \
+ shell=True, stdout=PIPE, stderr=PIPE)
+ ping_out = worker.communicate()[0]
+ if worker.returncode != 0:
+ io.append(mesh_net + ': ' + addr + ' -> ' + tgt + ': Failed')
+
+ return io
+
+def minion_list():
+
+ ''' List registered minions '''
+
+ return listdir('/etc/salt/pki/master/minions/')
+
+def verify_addresses():
+
+ ''' Verify addresses taken from pillars '''
+
+ nodes = nodes_addresses()
+ verifier = {}
+ failed = []
+
+ for node, nodeobj in nodes:
+ for item in nodeobj:
+ addr = item[1]
+ if addr in verifier:
+ failed.append([node,verifier[addr],addr])
+ else:
+ verifier[addr] = node
+
+ if failed:
+ logger.error("FAILED. Duplicates found")
+ logger.error(failed)
+ return False
+ else:
+ logger.setLevel(logging.INFO)
+ logger.info(["PASSED"])
+ return True
+
+def nodes_addresses():
+
+ ''' List servers addresses '''
+
+ compound = 'linux:network:interface'
+ out = __salt__['saltutil.cmd']( tgt='I@' + compound,
+ tgt_type='compound',
+ fun='pillar.get',
+ arg=[compound],
+ timeout=10
+ ) or None
+
+ servers = []
+ for minion in minion_list():
+ addresses = []
+ if minion in out:
+ ifaces = out[minion]['ret']
+ for iface in ifaces:
+ ifobj = ifaces[iface]
+ if ifobj['enabled'] and 'address' in ifobj:
+ if 'mesh' in ifobj:
+ mesh = ifobj['mesh']
+ else:
+ mesh = 'default'
+ addresses.append([mesh, ifobj['address']])
+ servers.append([minion,addresses])
+
+ return servers
+
+def get_mesh():
+
+ ''' Build addresses mesh '''
+
+ full_mesh = {}
+ nodes = nodes_addresses()
+
+ for node, nodeobj in nodes:
+ for item in nodeobj:
+ mesh = item[0]
+ addr = item[1]
+ if not mesh in full_mesh:
+ full_mesh[mesh] = []
+ full_mesh[mesh].append(addr)
+
+ for node, nodeobj in nodes:
+ for item in nodeobj:
+ mesh = item[0]
+ tgts = full_mesh[mesh]
+ item.append(tgts)
+
+ return nodes
+
+def ping_check():
+
+ ''' Ping addresses in a mesh '''
+
+ mesh = get_mesh()
+ out = __salt__['saltutil.cmd']( tgt='*',
+ tgt_type='glob',
+ fun='net_checks.mesh_ping',
+ arg=[mesh],
+ timeout=10
+ ) or None
+
+ failed = []
+
+ if out:
+ for minion in out:
+ ret = out[minion]['ret']
+ if ret:
+ failed.append(ret)
+ else:
+ failed = ["No response from minions"]
+
+ if failed:
+ logger.error("FAILED")
+ logger.error('\n'.join(str(x) for x in failed))
+ return False
+ else:
+ logger.setLevel(logging.INFO)
+ logger.info(["PASSED"])
+ return True
+
+def get_nics_csv(delim=","):
+
+ ''' List nics in csv format
+
+ :param delim: Delimiter char. Type: str
+
+ '''
+
+ header = "server,nic_name,ip_addr,mac_addr,link,chassis_id,chassis_name,port_mac,port_descr\n"
+ io = ""
+
+ # Try to reuse lldp output if possible
+ try:
+ lldp_info = Popen("lldpcli -f keyvalue s n s", shell=True, stdout=PIPE).communicate()[0]
+ except:
+ lldp_info = ""
+
+ for nic in get_nics():
+ lldp = ""
+ nic_name = nic[0]
+ if research('(one|ten|fourty)[0-9]+', nic_name):
+ # Check if we can fetch lldp data for that nic
+ for line in lldp_info.splitlines():
+ chassis = 'lldp.' + nic[0] + '.chassis'
+ port = 'lldp.' + nic[0] + '.port'
+ if chassis in line or port in line:
+ lldp += delim + line.split('=')[1]
+ if not lldp:
+ lldp = delim + delim + delim + delim
+
+ io += __salt__['config.get']('id') + \
+ delim + nic_name + \
+ delim + str(nic[1]).strip() + \
+ delim + str(nic[2]).strip() + \
+ delim + str(nic[3]).strip() + \
+ delim + str(nic[4]).strip() + \
+ lldp + "\n"
+
+ return header + io
diff --git a/linux/files/cron_users.jinja b/linux/files/cron_users.jinja
new file mode 100644
index 0000000..fe47059
--- /dev/null
+++ b/linux/files/cron_users.jinja
@@ -0,0 +1,5 @@
+# This file is managed by Salt, do not edit
+{%- for user_name in users %}
+{{ user_name }}
+{%- endfor %}
+{# IMPORTANT: This file SHOULD ends with a newline #}
\ No newline at end of file
diff --git a/linux/files/login.defs.jinja b/linux/files/login.defs.jinja
new file mode 100644
index 0000000..572c558
--- /dev/null
+++ b/linux/files/login.defs.jinja
@@ -0,0 +1,62 @@
+{%- from "linux/map.jinja" import login_defs with context -%}
+# This file is managed by Salt, do not edit
+{%- set allowed_options = [
+ 'CHFN_RESTRICT',
+ 'CONSOLE_GROUPS',
+ 'CREATE_HOME',
+ 'DEFAULT_HOME',
+ 'ENCRYPT_METHOD',
+ 'ENV_HZ',
+ 'ENV_PATH',
+ 'ENV_SUPATH',
+ 'ERASECHAR',
+ 'FAIL_DELAY',
+ 'FAKE_SHELL',
+ 'GID_MAX',
+ 'GID_MIN',
+ 'HUSHLOGIN_FILE',
+ 'KILLCHAR',
+ 'LOG_OK_LOGINS',
+ 'LOG_UNKFAIL_ENAB',
+ 'LOGIN_RETRIES',
+ 'LOGIN_TIMEOUT',
+ 'MAIL_DIR',
+ 'MAIL_FILE',
+ 'MAX_MEMBERS_PER_GROUP',
+ 'MD5_CRYPT_ENAB',
+ 'PASS_MAX_DAYS',
+ 'PASS_MIN_DAYS',
+ 'PASS_WARN_AGE',
+ 'SHA_CRYPT_MIN_ROUNDS',
+ 'SHA_CRYPT_MAX_ROUNDS',
+ 'SULOG_FILE',
+ 'SU_NAME',
+ 'SUB_GID_MIN',
+ 'SUB_GID_MAX',
+ 'SUB_GID_COUNT',
+ 'SUB_UID_MIN',
+ 'SUB_UID_MAX',
+ 'SUB_UID_COUNT',
+ 'SYS_GID_MAX',
+ 'SYS_GID_MIN',
+ 'SYS_UID_MAX',
+ 'SYS_UID_MIN',
+ 'SYSLOG_SG_ENAB',
+ 'SYSLOG_SU_ENAB',
+ 'TTYGROUP',
+ 'TTYPERM',
+ 'TTYTYPE_FILE',
+ 'UID_MAX',
+ 'UID_MIN',
+ 'UMASK',
+ 'USERDEL_CMD',
+ 'USERGROUPS_ENAB'
+] %}
+{%- for opt_name in allowed_options %}
+ {%- if opt_name in login_defs %}
+ {%- set opt_params = login_defs.get(opt_name) %}
+ {%- if opt_params.get('enabled', true) %}
+{{ opt_name.ljust(20) }} {{ opt_params.value }}
+ {%- endif %}
+ {%- endif %}
+{%- endfor %}
diff --git a/linux/files/preferences_repo b/linux/files/preferences_repo
index 603d313..91e9f9b 100644
--- a/linux/files/preferences_repo
+++ b/linux/files/preferences_repo
@@ -1,8 +1,19 @@
-{%- from "linux/map.jinja" import system with context %}
-{%- set repo = system.repo[repo_name] %}
-{%- for pin in repo.pin %}
-{%- set package = pin.get('package', '*') %}
+{%- from "linux/map.jinja" import system with context -%}
+{%- set repo = system.repo[repo_name] -%}
+{%- if repo.pinning is defined -%}
+ {%- for id,pin in repo.pinning|dictsort -%}
+ {% if pin.get('enabled', False) %}
+
+Package: {{ pin.get('package','*') }}
+Pin: {{ pin.pin }}
+Pin-Priority: {{ pin.priority }}
+ {%- endif %}
+ {%- endfor -%}
+{%- elif repo.pin is defined -%}
+ {%- for pin in repo.pin -%}
+ {%- set package = pin.get('package', '*') %}
Package: {{ package }}
Pin: {{ pin.pin }}
Pin-Priority: {{ pin.priority }}
-{% endfor %}
+ {%- endfor %}
+{%- endif -%}
diff --git a/linux/map.jinja b/linux/map.jinja
index c333a89..4f8b5b7 100644
--- a/linux/map.jinja
+++ b/linux/map.jinja
@@ -85,6 +85,24 @@
},
}, grain='os_family', merge=salt['pillar.get']('linux:system')) %}
+{% set at = salt['grains.filter_by']({
+ 'Debian': {
+ 'enabled': false,
+ 'pkgs': ['at'],
+ 'services': ['atd'],
+ 'user': {}
+ },
+}, grain='os_family', merge=salt['pillar.get']('linux:system:at')) %}
+
+{% set cron = salt['grains.filter_by']({
+ 'Debian': {
+ 'enabled': false,
+ 'pkgs': ['cron'],
+ 'services': ['cron'],
+ 'user': {}
+ },
+}, grain='os_family', merge=salt['pillar.get']('linux:system:cron')) %}
+
{% set banner = salt['grains.filter_by']({
'BaseDefaults': {
'enabled': false,
@@ -122,6 +140,70 @@
},
}, grain='os_family', merge=salt['pillar.get']('linux:system:auth:ldap')) %}
+{%- load_yaml as login_defs_defaults %}
+Debian:
+ CHFN_RESTRICT:
+ value: 'rwh'
+ DEFAULT_HOME:
+ value: 'yes'
+ ENCRYPT_METHOD:
+ value: 'SHA512'
+ ENV_PATH:
+ value: 'PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games'
+ ENV_SUPATH:
+ value: 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
+ ERASECHAR:
+ value: '0177'
+ FAILLOG_ENAB:
+ value: 'yes'
+ FTMP_FILE:
+ value: '/var/log/btmp'
+ GID_MAX:
+ value: '60000'
+ GID_MIN:
+ value: '1000'
+ HUSHLOGIN_FILE:
+ value: '.hushlogin'
+ KILLCHAR:
+ value: '025'
+ LOGIN_RETRIES:
+ value: '5'
+ LOGIN_TIMEOUT:
+ value: '60'
+ LOG_OK_LOGINS:
+ value: 'no'
+ LOG_UNKFAIL_ENAB:
+ value: 'no'
+ MAIL_DIR:
+ value: '/var/mail'
+ PASS_MAX_DAYS:
+ value: '99999'
+ PASS_MIN_DAYS:
+ value: '0'
+ PASS_WARN_AGE:
+ value: '7'
+ SU_NAME:
+ value: 'su'
+ SYSLOG_SG_ENAB:
+ value: 'yes'
+ SYSLOG_SU_ENAB:
+ value: 'yes'
+ TTYGROUP:
+ value: 'tty'
+ TTYPERM:
+ value: '0600'
+ UID_MAX:
+ value: '60000'
+ UID_MIN:
+ value: '1000'
+ UMASK:
+ value: '022'
+ USERGROUPS_ENAB:
+ value: 'yes'
+{%- endload %}
+{%- set login_defs = salt['grains.filter_by'](login_defs_defaults,
+ grain='os_family', merge=salt['pillar.get']('linux:system:login_defs')) %}
+
{# 'network_name', #}
{% set interface_params = [
diff --git a/linux/meta/fluentd.yml b/linux/meta/fluentd.yml
index a6f9cc4..f6d6720 100644
--- a/linux/meta/fluentd.yml
+++ b/linux/meta/fluentd.yml
@@ -77,6 +77,8 @@
record:
- name: severity_label
value: '${ {"TRACE"=>8,"DEBUG"=>7,"INFO"=>6,"NOTICE"=>5,"WARNING"=>4,"ERROR"=>3,"CRITICAL"=>2,"ALERT"=>1,"EMERGENCY"=>0}.key(record["Severity"].to_i) }'
+ - name: source
+ value: systemd
match:
rewrite_tag:
tag: systemd.source
@@ -84,9 +86,9 @@
rule:
- name: ident
regexp: '^(.*)$'
- result: __TAG__.$1
+ result: $1.systemd
push_to_default:
- tag: 'systemd.source.*'
+ tag: '*.systemd'
type: copy
store:
- type: relabel
diff --git a/linux/network/dpdk.sls b/linux/network/dpdk.sls
index 2c7dcb9..786f7c8 100644
--- a/linux/network/dpdk.sls
+++ b/linux/network/dpdk.sls
@@ -106,7 +106,7 @@
linux_network_dpdk_bond_interface_{{ interface_name }}:
cmd.run:
- name: "ovs-vsctl{%- if network.ovs_nowait %} --no-wait{%- endif %} add-bond {{ interface.bridge }} {{ interface_name }} {{ bond_interfaces.keys()|join(' ') }}"
- - unless: "ovs-vsctl show | grep {{ interface_name }}"
+ - unless: "ovs-vsctl list-ports {{ interface.bridge }} | grep -w {{ interface_name }}"
- require:
- cmd: linux_network_dpdk_bridge_interface_{{ interface.bridge }}
@@ -178,8 +178,8 @@
linux_network_dpdk_bridge_port_interface_{{ interface_name }}:
cmd.run:
- - name: "ovs-vsctl{%- if network.ovs_nowait %} --no-wait{%- endif %} add-port {{ interface.bridge }} dpdk0 -- set Interface dpdk0 type=dpdk options:dpdk-devargs={{ interface.pci }}"
- - unless: "ovs-vsctl show | grep dpdk0"
+ - name: "ovs-vsctl{%- if network.ovs_nowait %} --no-wait{%- endif %} add-port {{ interface.bridge }} {{ interface_name }} -- set Interface {{ interface_name }} type=dpdk options:dpdk-devargs={{ interface.pci }}"
+ - unless: "ovs-vsctl list-ports {{ interface.bridge }} | grep -w {{ interface_name }}"
- require:
- cmd: linux_network_dpdk_bridge_interface_{{ interface.bridge }}
diff --git a/linux/network/interface.sls b/linux/network/interface.sls
index c2d2a23..a39fc37 100644
--- a/linux/network/interface.sls
+++ b/linux/network/interface.sls
@@ -2,7 +2,8 @@
{%- from "linux/map.jinja" import system with context %}
{%- if network.enabled %}
-{%- if network.get('dpdk', {}).get('enabled', False) %}
+{%- set dpdk_enabled = network.get('dpdk', {}).get('enabled', False) %}
+{%- if dpdk_enabled %}
include:
- linux.network.dpdk
{%- endif %}
@@ -117,7 +118,7 @@
- name: {{ interface_name }}
- bridge: {{ interface.bridge }}
- require:
- {%- if network.interface.get(interface.bridge, {}).get('type', 'ovs_bridge') == 'dpdk_ovs_bridge' %}
+ {%- if dpdk_enabled and network.interface.get(interface.bridge, {}).get('type', 'ovs_bridge') == 'dpdk_ovs_bridge' %}
- cmd: linux_network_dpdk_bridge_interface_{{ interface.bridge }}
{%- else %}
- openvswitch_bridge: ovs_bridge_{{ interface.bridge }}
diff --git a/linux/storage/swap.sls b/linux/storage/swap.sls
index 7b8d82e..3b3fd80 100644
--- a/linux/storage/swap.sls
+++ b/linux/storage/swap.sls
@@ -53,6 +53,24 @@
{%- endif %}
+{%- else %}
+
+{{ swap.device }}:
+ module.run:
+ - name: mount.rm_fstab
+ - m_name: none
+ - device: {{ swap.device }}
+ - onlyif: grep -q {{ swap.device }} /etc/fstab
+
+linux_disable_swap_{{ swap.engine }}_{{ swap.device }}:
+ cmd.run:
+ {%- if swap.engine == 'partition' %}
+ - name: 'swapoff {{ swap.device }}'
+ {%- elif swap.engine == 'file' %}
+ - name: 'swapoff {{ swap.device }} && rm -f {{ swap.device }}'
+ {%- endif %}
+ - onlyif: file -L -s {{ swap.device }} | grep -q 'swap file'
+
{%- endif %}
{%- endfor %}
diff --git a/linux/system/at.sls b/linux/system/at.sls
new file mode 100644
index 0000000..864ae0c
--- /dev/null
+++ b/linux/system/at.sls
@@ -0,0 +1,62 @@
+{%- from "linux/map.jinja" import system, at with context %}
+
+{%- if at.get('enabled', false) %}
+
+at_packages:
+ pkg.installed:
+ - names: {{ at.pkgs }}
+
+at_services:
+ service.running:
+ - enable: true
+ - names: {{ at.services }}
+ - require:
+ - pkg: at_packages
+ {%- if grains.get('noservices') %}
+ - onlyif: /bin/false
+ {%- endif %}
+
+ {%- set allow_users = [] %}
+ {%- for user_name, user_params in at.get('user', {}).items() %}
+ {%- set user_enabled = user_params.get('enabled', false) and
+ system.get('user', {}).get(
+ user_name, {'enabled': true}).get('enabled', true) %}
+ {%- if user_enabled %}
+ {%- do allow_users.append(user_name) %}
+ {%- endif %}
+ {%- endfor %}
+
+etc_at_allow:
+ {%- if allow_users %}
+ file.managed:
+ - name: /etc/at.allow
+ - template: jinja
+ - source: salt://linux/files/cron_users.jinja
+ - user: root
+ - group: daemon
+ - mode: 0640
+ - defaults:
+ users: {{ allow_users | yaml }}
+ - require:
+ - cron_packages
+ {%- else %}
+ file.absent:
+ - name: /etc/at.allow
+ {%- endif %}
+
+
+{#
+ /etc/at.deny should be absent to comply with
+ CIS 5.1.8 Ensure at/cron is restricted to authorized users
+#}
+etc_at_deny:
+ file.absent:
+ - name: /etc/at.deny
+
+{%- else %}
+
+fake_linux_system_at:
+ test.nop:
+ - comment: Fake state to satisfy 'require sls:linux.system.at'
+
+{%- endif %}
diff --git a/linux/system/cron.sls b/linux/system/cron.sls
new file mode 100644
index 0000000..a5f57a4
--- /dev/null
+++ b/linux/system/cron.sls
@@ -0,0 +1,87 @@
+{%- from "linux/map.jinja" import system, cron with context %}
+
+{%- if cron.get('enabled', false) %}
+
+cron_packages:
+ pkg.installed:
+ - names: {{ cron.pkgs }}
+
+cron_services:
+ service.running:
+ - enable: true
+ - names: {{ cron.services }}
+ - require:
+ - pkg: cron_packages
+ {%- if grains.get('noservices') %}
+ - onlyif: /bin/false
+ {%- endif %}
+
+ {%- set allow_users = [] %}
+ {%- for user_name, user_params in cron.get('user', {}).items() %}
+ {%- set user_enabled = user_params.get('enabled', false) and
+ system.get('user', {}).get(
+ user_name, {'enabled': true}).get('enabled', true) %}
+ {%- if user_enabled %}
+ {%- do allow_users.append(user_name) %}
+ {%- endif %}
+ {%- endfor %}
+
+etc_cron_allow:
+ {%- if allow_users %}
+ file.managed:
+ - name: /etc/cron.allow
+ - template: jinja
+ - source: salt://linux/files/cron_users.jinja
+ - user: root
+ - group: crontab
+ - mode: 0640
+ - defaults:
+ users: {{ allow_users | yaml }}
+ - require:
+ - cron_packages
+ {%- else %}
+ file.absent:
+ - name: /etc/cron.allow
+ {%- endif %}
+
+{#
+ /etc/cron.deny should be absent to comply with
+ CIS 5.1.8 Ensure at/cron is restricted to authorized users
+#}
+etc_cron_deny:
+ file.absent:
+ - name: /etc/cron.deny
+
+etc_crontab:
+ file.managed:
+ - name: /etc/crontab
+ - user: root
+ - group: root
+ - mode: 0600
+ - replace: False
+ - require:
+ - cron_packages
+
+etc_cron_dirs:
+ file.directory:
+ - names:
+ - /etc/cron.d
+ - /etc/cron.daily
+ - /etc/cron.hourly
+ - /etc/cron.monthly
+ - /etc/cron.weekly
+ - user: root
+ - group: root
+ - dir_mode: 0600
+ - recurse:
+ - ignore_files
+ - require:
+ - cron_packages
+
+{%- else %}
+
+fake_linux_system_cron:
+ test.nop:
+ - comment: Fake state to satisfy 'require sls:linux.system.cron'
+
+{%- endif %}
diff --git a/linux/system/grub.sls b/linux/system/grub.sls
index 74ea553..49277ff 100644
--- a/linux/system/grub.sls
+++ b/linux/system/grub.sls
@@ -7,6 +7,7 @@
- makedirs: True
{%- if grains['os_family'] == 'RedHat' %}
+ {%- set boot_grub_cfg = '/boot/grub2/grub.cfg' %}
/etc/default/grub:
file.append:
- text:
@@ -14,14 +15,26 @@
grub_update:
cmd.wait:
- - name: grub2-mkconfig -o /boot/grub2/grub.cfg
+ - name: grub2-mkconfig -o {{ boot_grub_cfg }}
{%- else %}
+ {%- set boot_grub_cfg = '/boot/grub/grub.cfg' %}
-{%- if grains.get('virtual_subtype', None) not in ['Docker', 'LXC'] %}
grub_update:
cmd.wait:
- name: update-grub
-{%- endif %}
+ {%- if grains.get('virtual_subtype') in ['Docker', 'LXC'] %}
+ - onlyif: /bin/false
+ {%- endif %}
{%- endif %}
+
+grub_cfg_permissions:
+ file.managed:
+ - name: {{ boot_grub_cfg }}
+ - user: 'root'
+ - owner: 'root'
+ - mode: '400'
+ - onlyif: test -f {{ boot_grub_cfg }}
+ - require:
+ - cmd: grub_update
diff --git a/linux/system/init.sls b/linux/system/init.sls
index ad3681a..20d39d9 100644
--- a/linux/system/init.sls
+++ b/linux/system/init.sls
@@ -3,6 +3,12 @@
include:
- linux.system.env
- linux.system.profile
+- linux.system.shell
+{%- if system.login_defs is defined %}
+- linux.system.login_defs
+{%- endif %}
+- linux.system.at
+- linux.system.cron
{%- if system.repo|length > 0 %}
- linux.system.repo
{%- endif %}
diff --git a/linux/system/job.sls b/linux/system/job.sls
index af42b58..4cdb946 100644
--- a/linux/system/job.sls
+++ b/linux/system/job.sls
@@ -3,45 +3,46 @@
include:
- linux.system.user
+- linux.system.cron
-{%- for name, job in system.job.items() %}
+ {%- for name, job in system.job.items() %}
+ {%- set job_user = job.get('user', 'root') %}
linux_job_{{ job.command }}:
- {%- if job.enabled|default(True) %}
+ {%- if job.get('enabled', True) %}
cron.present:
- name: >
{{ job.command }}
- {%- if job.get('identifier', True) %}
+ {%- if job.get('identifier', True) %}
- identifier: {{ job.get('identifier', job.get('name', name)) }}
- {%- endif %}
- - user: {{ job.user|default("root") }}
- {%- if job.minute is defined %}
+ {%- endif %}
+ - user: {{ job_user }}
+ {%- if job.minute is defined %}
- minute: '{{ job.minute }}'
- {%- endif %}
- {%- if job.hour is defined %}
+ {%- endif %}
+ {%- if job.hour is defined %}
- hour: '{{ job.hour }}'
- {%- endif %}
- {%- if job.daymonth is defined %}
+ {%- endif %}
+ {%- if job.daymonth is defined %}
- daymonth: '{{ job.daymonth }}'
- {%- endif %}
- {%- if job.month is defined %}
+ {%- endif %}
+ {%- if job.month is defined %}
- month: '{{ job.month }}'
- {%- endif %}
- {%- if job.dayweek is defined %}
+ {%- endif %}
+ {%- if job.dayweek is defined %}
- dayweek: '{{ job.dayweek }}'
- {%- endif %}
- {%- if job.user|default("root") in system.get('user', {}).keys() %}
+ {%- endif %}
- require:
- - user: system_user_{{ job.user|default("root") }}
- {%- endif %}
- {%- else %}
+ - sls: linux.system.cron
+ {%- if job_user in system.get('user', {}).keys() %}
+ - user: system_user_{{ job_user }}
+ {%- endif %}
+ {%- else %}
cron.absent:
- name: {{ job.command }}
- {%- if job.get('identifier', True) %}
+ {%- if job.get('identifier', True) %}
- identifier: {{ job.get('identifier', job.get('name', name)) }}
+ {%- endif %}
{%- endif %}
- {%- endif %}
-
-{%- endfor %}
-
+ {%- endfor %}
{%- endif %}
diff --git a/linux/system/kernel.sls b/linux/system/kernel.sls
index e6111c5..3dc3046 100644
--- a/linux/system/kernel.sls
+++ b/linux/system/kernel.sls
@@ -8,10 +8,10 @@
{%- do kernel_boot_opts.append('elevator=' ~ system.kernel.elevator) if system.kernel.elevator is defined %}
{%- do kernel_boot_opts.extend(system.kernel.boot_options) if system.kernel.boot_options is defined %}
-{%- if kernel_boot_opts %}
include:
- linux.system.grub
+{%- if kernel_boot_opts %}
/etc/default/grub.d/99-custom-settings.cfg:
file.managed:
- contents: 'GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT {{ kernel_boot_opts|join(' ') }}"'
diff --git a/linux/system/login_defs.sls b/linux/system/login_defs.sls
new file mode 100644
index 0000000..f94348a
--- /dev/null
+++ b/linux/system/login_defs.sls
@@ -0,0 +1,13 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+ {%- if system.login_defs is defined %}
+login_defs:
+ file.managed:
+ - name: /etc/login.defs
+ - source: salt://linux/files/login.defs.jinja
+ - template: jinja
+ - user: root
+ - group: root
+ - mode: 644
+ {%- endif %}
+{%- endif %}
diff --git a/linux/system/repo.sls b/linux/system/repo.sls
index 0c0b026..dd41afe 100644
--- a/linux/system/repo.sls
+++ b/linux/system/repo.sls
@@ -57,7 +57,7 @@
file.absent
{%- endif %}
- {%- if repo.pin is defined %}
+ {%- if repo.pin is defined or repo.pinning is defined %}
linux_repo_{{ name }}_pin:
file.managed:
- name: /etc/apt/preferences.d/{{ name }}
diff --git a/linux/system/shell.sls b/linux/system/shell.sls
new file mode 100644
index 0000000..29fc1dc
--- /dev/null
+++ b/linux/system/shell.sls
@@ -0,0 +1,45 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+ {%- if system.shell is defined %}
+
+ {%- if system.shell.umask is defined %}
+etc_bash_bashrc_umask:
+ file.blockreplace:
+ - name: /etc/bash.bashrc
+ - marker_start: "# BEGIN CIS 5.4.4 default user umask"
+ - marker_end: "# END CIS 5.4.4 default user umask"
+ - content: "umask {{ system.shell.umask }}"
+ - append_if_not_found: True
+ - onlyif: test -f /etc/bash.bashrc
+
+etc_profile_umask:
+ file.blockreplace:
+ - name: /etc/profile
+ - marker_start: "# BEGIN CIS 5.4.4 default user umask"
+ - marker_end: "# END CIS 5.4.4 default user umask"
+ - content: "umask {{ system.shell.umask }}"
+ - append_if_not_found: True
+ - onlyif: test -f /etc/profile
+ {%- endif %}
+
+ {%- if system.shell.timeout is defined %}
+etc_bash_bashrc_timeout:
+ file.blockreplace:
+ - name: /etc/bash.bashrc
+ - marker_start: "# BEGIN CIS 5.4.5 default user shell timeout"
+ - marker_end: "# END CIS 5.4.5 default user shell timeout"
+ - content: "TMOUT={{ system.shell.timeout }}"
+ - append_if_not_found: True
+ - onlyif: test -f /etc/bash.bashrc
+
+etc_profile_timeout:
+ file.blockreplace:
+ - name: /etc/profile
+ - marker_start: "# BEGIN CIS 5.4.5 default user shell timeout"
+ - marker_end: "# END CIS 5.4.5 default user shell timeout"
+ - content: "TMOUT={{ system.shell.timeout }}"
+ - append_if_not_found: True
+ - onlyif: test -f /etc/profile
+ {%- endif %}
+ {%- endif %}
+{%- endif %}
diff --git a/linux/system/sysfs.sls b/linux/system/sysfs.sls
index 8440384..a4e28bf 100644
--- a/linux/system/sysfs.sls
+++ b/linux/system/sysfs.sls
@@ -11,6 +11,8 @@
- require:
- pkg: linux_sysfs_package
+{% set apply = system.get('sysfs', {}).pop('enable_apply', True) %}
+
{%- for name, sysfs in system.get('sysfs', {}).items() %}
/etc/sysfs.d/{{ name }}.conf:
@@ -32,6 +34,8 @@
{%- set sysfs_list = sysfs %}
{%- endif %}
+{%- if apply %}
+
{%- for item in sysfs_list %}
{%- set list_idx = loop.index %}
{%- for key, value in item.items() %}
@@ -48,4 +52,7 @@
{%- endfor %}
{%- endfor %}
+
+{%- endif %}
+
{%- endfor %}
diff --git a/linux/system/user.sls b/linux/system/user.sls
index 7ffdae6..89d2cbb 100644
--- a/linux/system/user.sls
+++ b/linux/system/user.sls
@@ -43,12 +43,25 @@
{%- endif %}
{%- if user.system is defined and user.system %}
- system: True
+ - shell: {{ user.get('shell', '/bin/false') }}
{%- else %}
- shell: {{ user.get('shell', '/bin/bash') }}
{%- endif %}
{%- if user.uid is defined and user.uid %}
- uid: {{ user.uid }}
{%- endif %}
+ {%- if user.maxdays is defined %}
+ - maxdays: {{ user.maxdays }}
+ {%- endif %}
+ {%- if user.mindays is defined %}
+ - mindays: {{ user.mindays }}
+ {%- endif %}
+ {%- if user.warndays is defined %}
+ - warndays: {{ user.warndays }}
+ {%- endif %}
+ {%- if user.inactdays is defined %}
+ - inactdays: {{ user.inactdays }}
+ {%- endif %}
- require: {{ requires|yaml }}
system_user_home_{{ user.home }}:
diff --git a/metadata/service/system/cis/cis-1-1-1-1.yml b/metadata/service/system/cis/cis-1-1-1-1.yml
new file mode 100644
index 0000000..2331a54
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-1-1.yml
@@ -0,0 +1,37 @@
+# 1.1.1.1 Ensure mounting of cramfs filesystems is disabled
+#
+# Description
+# ===========
+# The cramfs filesystem type is a compressed read-only Linux filesystem
+# embedded in small footprint systems. A cramfs image can be used without
+# having to first decompress the image.
+#
+# Rationale
+# =========
+# Removing support for unneeded filesystem types reduces the local attack
+# surface of the server. If this filesystem type is not needed, disable it.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v cramfs
+# install /bin/true
+# # lsmod | grep cramfs
+# <No output>
+#
+# Remediation
+# ===========
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install cramfs /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ cramfs:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-1-1-1-2.yml b/metadata/service/system/cis/cis-1-1-1-2.yml
new file mode 100644
index 0000000..f84b56f
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-1-2.yml
@@ -0,0 +1,36 @@
+# 1.1.1.2 Ensure mounting of freevxfs filesystems is disabled
+#
+# Description
+# ===========
+# The freevxfs filesystem type is a free version of the Veritas type
+# filesystem. This is the primary filesystem type for HP-UX operating systems.
+#
+# Rationale
+# =========
+# Removing support for unneeded filesystem types reduces the local attack
+# surface of the system. If this filesystem type is not needed, disable it.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v freevxfs
+# install /bin/true
+# # lsmod | grep freevxfs
+# <No output>
+#
+# Remediation
+# ===========
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install freevxfs /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ freevxfs:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-1-1-1-3.yml b/metadata/service/system/cis/cis-1-1-1-3.yml
new file mode 100644
index 0000000..91390b5
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-1-3.yml
@@ -0,0 +1,36 @@
+# 1.1.1.3 Ensure mounting of jffs2 filesystems is disabled
+#
+# Description
+# ===========
+# The jffs2 (journaling flash filesystem 2) filesystem type is a
+# log-structured filesystem used in flash memory devices.
+#
+# Rationale
+# =========
+# Removing support for unneeded filesystem types reduces the local attack
+# surface of the system. If this filesystem type is not needed, disable it.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v jffs2
+# install /bin/true
+# # lsmod | grep jffs2
+# <No output>
+#
+# Remediation
+# ===========
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install jffs2 /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ jffs2:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-1-1-1-4.yml b/metadata/service/system/cis/cis-1-1-1-4.yml
new file mode 100644
index 0000000..c246ad2
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-1-4.yml
@@ -0,0 +1,36 @@
+# 1.1.1.4 Ensure mounting of hfs filesystems is disabled
+#
+# Description
+# ===========
+# The hfs filesystem type is a hierarchical filesystem that allows
+# you to mount Mac OS filesystems.
+#
+# Rationale
+# =========
+# Removing support for unneeded filesystem types reduces the local attack
+# surface of the system. If this filesystem type is not needed, disable it.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v hfs
+# install /bin/true
+# # lsmod | grep hfs
+# <No output>
+#
+# Remediation
+# ===========
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install hfs /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ hfs:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-1-1-1-5.yml b/metadata/service/system/cis/cis-1-1-1-5.yml
new file mode 100644
index 0000000..e258052
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-1-5.yml
@@ -0,0 +1,36 @@
+# 1.1.1.5 Ensure mounting of hfsplus filesystems is disabled
+#
+# Description
+# ===========
+# The hfsplus filesystem type is a hierarchical filesystem designed to
+# replace hfs that allows you to mount Mac OS filesystems.
+#
+# Rationale
+# =========
+# Removing support for unneeded filesystem types reduces the local attack
+# surface of the system. If this filesystem type is not needed, disable it.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v hfsplus
+# install /bin/true
+# # lsmod | grep hfsplus
+# <No output>
+#
+# Remediation
+# ===========
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install hfsplus /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ hfsplus:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-1-1-1-6.yml b/metadata/service/system/cis/cis-1-1-1-6.yml
new file mode 100644
index 0000000..59da5db
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-1-6.yml
@@ -0,0 +1,43 @@
+# 1.1.1.6 Ensure mounting of squashfs filesystems is disabled
+#
+# Description
+# ===========
+# The squashfs filesystem type is a compressed read-only Linux filesystem
+# embedded in small footprint systems (similar to cramfs). A squashfs image
+# can be used without having to first decompress the image.
+#
+# Rationale
+# =========
+# Removing support for unneeded filesystem types reduces the local attack
+# surface of the server. If this filesystem type is not needed, disable it.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v squashfs
+# install /bin/true
+# # lsmod | grep squashfs
+# <No output>
+#
+# Remediation
+# ===========
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install squashfs /bin/true
+#
+# NOTE
+# ====
+# In Ubuntu 16.04 squashfs is built into kernel, and 'install' command
+# from modprobe.d dir has no effect. However, this is still checked by
+# CIS-CAT in Ubuntu 16.04 benchmark v.1.0.0. This was removed in v.1.1.0.
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ squashfs:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-1-1-1-7.yml b/metadata/service/system/cis/cis-1-1-1-7.yml
new file mode 100644
index 0000000..0102220
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-1-7.yml
@@ -0,0 +1,38 @@
+# 1.1.1.7 Ensure mounting of udf filesystems is disabled
+#
+# Description
+# ===========
+# The udf filesystem type is the universal disk format used to implement
+# ISO/IEC 13346 and ECMA-167 specifications. This is an open vendor filesystem
+# type for data storage on a broad range of media. This filesystem type is
+# necessary to support writing DVDs and newer optical disc formats.
+#
+# Rationale
+# =========
+# Removing support for unneeded filesystem types reduces the local attack
+# surface of the server. If this filesystem type is not needed, disable it.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v udf
+# install /bin/true
+# # lsmod | grep udf
+# <No output>
+#
+# Remediation
+# ===========
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install udf /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ udf:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-1-1-1-8.yml b/metadata/service/system/cis/cis-1-1-1-8.yml
new file mode 100644
index 0000000..7c06c8e
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-1-8.yml
@@ -0,0 +1,50 @@
+# 1.1.1.8 Ensure mounting of FAT filesystems is disabled
+#
+# Description
+# ===========
+# The FAT filesystem format is primarily used on older windows systems and
+# portable USB drives or flash modules. It comes in three types FAT12, FAT16,
+# and FAT32 all of which are supported by the vfat kernel module.
+#
+# Rationale
+# =========
+# Removing support for unneeded filesystem types reduces the local attack
+# surface of the server. If this filesystem type is not needed, disable it.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v vfat
+# install /bin/true
+# # lsmod | grep vfat
+# <No output>
+#
+# Remediation
+# ===========
+#
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install vfat /bin/true
+#
+# Impact
+# ======
+# FAT filesystems are often used on portable USB sticks and other flash
+# media are commonly used to transfer files between workstations, removing
+# VFAT support may prevent the ability to transfer files in this way.
+#
+# NOTE
+# ====
+# In Ubuntu 16.04 vfat is built into kernel, and 'install' command
+# from modprobe.d dir has no effect. However, this is still checked by
+# CIS-CAT in Ubuntu 16.04 benchmark v.1.0.0. This was removed in v.1.1.0.
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ vfat:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-1-1-14_15_16.yml b/metadata/service/system/cis/cis-1-1-14_15_16.yml
new file mode 100644
index 0000000..d9c7e72
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-14_15_16.yml
@@ -0,0 +1,95 @@
+# CIS 1.1.14 Ensure nodev option set on /dev/shm partition (Scored)
+#
+# Description
+# ===========
+# The nodev mount option specifies that the filesystem cannot contain special
+# devices.
+#
+# Rationale
+# =========
+# Since the /run/shm filesystem is not intended to support devices, set this
+# option to ensure that users cannot attempt to create special devices in
+# /dev/shm partitions.
+#
+# Audit
+# =====
+# Run the following command and verify that the nodev option is set on /dev/shm .
+#
+# # mount | grep /dev/shm
+# shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime)
+#
+# Remediation
+# ===========
+#
+# Edit the /etc/fstab file and add nodev to the fourth field (mounting options)
+# for the /dev/shm partition. See the fstab(5) manual page for more information.
+# Run the following command to remount /dev/shm :
+#
+# # mount -o remount,nodev /dev/shm
+#
+# CIS 1.1.15 Ensure nosuid option set on /dev/shm partition (Scored)
+#
+# Description
+# ===========
+# The nosuid mount option specifies that the filesystem cannot contain setuid
+# files.
+#
+# Rationale
+# =========
+# Setting this option on a file system prevents users from introducing
+# privileged programs onto the system and allowing non-root users to execute them.
+#
+# Audit
+# =====
+# Run the following command and verify that the no suid option is set on /dev/shm .
+#
+# # mount | grep /dev/shm
+# shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime)
+#
+# Remediation
+# ===========
+# Edit the /etc/fstab file and add nosuid to the fourth field (mounting options)
+# for the /dev/shm partition. See the fstab(5) manual page for more information.
+# Run the following command to remount /dev/shm :
+#
+# # mount -o remount,nosuid /dev/shm
+#
+# 1.1.16 Ensure noexec option set on /dev/shm partition (Scored)
+#
+# Description
+# ===========
+# The noexec mount option specifies that the filesystem cannot contain
+# executable binaries.
+#
+# Rationale
+# =========
+# Setting this option on a file system prevents users from executing programs
+# from shared memory. This deters users from introducing potentially malicious
+# software on the system.
+#
+# Audit
+# =====
+# Run the following command and verify that the noexec option is set on /run/shm .
+#
+# # mount | grep /dev/shm
+# shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime)
+#
+# Remediation
+# ===========
+# Edit the /etc/fstab file and add noexec to the fourth field (mounting options)
+# for the /dev/shm partition. See the fstab(5) manual page for more information.
+# Run the following command to remount /dev/shm :
+#
+# # mount -o remount,noexec /dev/shm
+#
+parameters:
+ linux:
+ storage:
+ mount:
+ ensure_dev_shm_mount_options:
+ enabled: true
+ file_system: tmpfs
+ device: shm
+ path: /dev/shm
+ opts: rw,nosuid,nodev,noexec,relatime
+
diff --git a/metadata/service/system/cis/cis-1-1-21.yml b/metadata/service/system/cis/cis-1-1-21.yml
new file mode 100644
index 0000000..da84f49
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-1-21.yml
@@ -0,0 +1,53 @@
+# CIS 1.1.21 Disable Automounting
+#
+# Description
+# ===========
+# autofs allows automatic mounting of devices, typically including CD/DVDs
+# and USB drives.
+#
+# Rationale
+# =========
+# With automounting enabled anyone with physical access could attach a USB
+# drive or disc and have its contents available in system even if they lacked
+# permissions to mount it themselves.
+#
+# Audit
+# =====
+# Run the following command to verify autofs is not enabled:
+#
+# # systemctl is-enabled autofs
+# disabled
+#
+# Verify result is not "enabled".
+#
+# Remediation
+# ===========
+#
+# Run the following command to disable autofs :
+#
+# # systemctl disable autofs
+#
+# Impact
+# ======
+# The use portable hard drives is very common for workstation users. If your
+# organization allows the use of portable storage or media on workstations
+# and physical access controls to workstations is considered adequate there
+# is little value add in turning off automounting.
+#
+# Notes
+# =====
+# This control should align with the tolerance of the use of portable drives
+# and optical media in the organization. On a server requiring an admin to
+# manually mount media can be part of defense-in-depth to reduce the risk of
+# unapproved software or information being introduced or proprietary software
+# or information being exfiltrated. If admins commonly use flash drives and
+# Server access has sufficient physical controls, requiring manual mounting
+# may not increase security.
+#
+parameters:
+ linux:
+ system:
+ service:
+ autofs:
+ status: disabled
+
diff --git a/metadata/service/system/cis/cis-1-5-4.yml b/metadata/service/system/cis/cis-1-5-4.yml
new file mode 100644
index 0000000..5583d80
--- /dev/null
+++ b/metadata/service/system/cis/cis-1-5-4.yml
@@ -0,0 +1,37 @@
+# CIS 1.5.4 Ensure prelink is disabled
+#
+# Description
+# ===========
+# prelink is a program that modifies ELF shared libraries and ELF dynamically
+# linked binaries in such a way that the time needed for the dynamic linker to
+# perform relocations at startup significantly decreases.
+#
+# Rationale
+# =========
+# The prelinking feature can interfere with the operation of AIDE, because it
+# changes binaries. Prelinking can also increase the vulnerability of the system
+# if a malicious user is able to compromise a common library such as libc.
+#
+# Audit
+# =====
+# Run the following command and verify prelink is not installed:
+#
+# # dpkg -s prelink
+#
+# Remediation
+# ===========
+# Run the following command to restore binaries to normal:
+#
+# # prelink -ua
+#
+# Run the following command to uninstall prelink :
+#
+# # apt-get remove prelink
+#
+parameters:
+ linux:
+ system:
+ package:
+ prelink:
+ version: removed
+
diff --git a/metadata/service/system/cis/cis-2-3-1.yml b/metadata/service/system/cis/cis-2-3-1.yml
new file mode 100644
index 0000000..6116f36
--- /dev/null
+++ b/metadata/service/system/cis/cis-2-3-1.yml
@@ -0,0 +1,43 @@
+# 2.3.1 Ensure NIS Client is not installed
+#
+# Description
+# ===========
+# The Network Information Service (NIS), formerly known as Yellow Pages,
+# is a client-server directory service protocol used to distribute system
+# configuration files. The NIS client ( ypbind ) was used to bind a machine
+# to an NIS server and receive the distributed configuration files.
+#
+# Rationale
+# =========
+# The NIS service is inherently an insecure system that has been vulnerable
+# to DOS attacks, buffer overflows and has poor authentication for querying
+# NIS maps. NIS generally has been replaced by such protocols as Lightweight
+# Directory Access Protocol (LDAP). It is recommended that the service be
+# removed.
+#
+# Audit
+# =====
+# Run the following command and verify nis is not installed:
+#
+# dpkg -s nis
+#
+# Remediation
+# ===========
+# Run the following command to uninstall nis:
+#
+# apt-get remove nis
+#
+# Impact
+# ======
+# Many insecure service clients are used as troubleshooting tools and in
+# testing environments. Uninstalling them can inhibit capability to test
+# and troubleshoot. If they are required it is advisable to remove the clients
+# after use to prevent accidental or intentional misuse.
+#
+parameters:
+ linux:
+ system:
+ package:
+ nis:
+ version: removed
+
diff --git a/metadata/service/system/cis/cis-2-3-2.yml b/metadata/service/system/cis/cis-2-3-2.yml
new file mode 100644
index 0000000..ecbfa6a
--- /dev/null
+++ b/metadata/service/system/cis/cis-2-3-2.yml
@@ -0,0 +1,55 @@
+# 2.3.2 Ensure rsh client is not installed
+#
+# Description
+# ===========
+# The rsh package contains the client commands for the rsh services.
+#
+# Rationale
+# =========
+# These legacy clients contain numerous security exposures and have been
+# replaced with the more secure SSH package. Even if the server is removed,
+# it is best to ensure the clients are also removed to prevent users from
+# inadvertently attempting to use these commands and therefore exposing
+# their credentials. Note that removing the rsh package removes the
+# clients for rsh , rcp and rlogin .
+#
+# Audit
+# =====
+# Run the following commands and verify rsh is not installed:
+#
+# dpkg -s rsh-client
+# dpkg -s rsh-redone-client
+#
+# Remediation
+# ===========
+# Run the following command to uninstall rsh :
+#
+# apt-get remove rsh-client rsh-redone-client
+#
+# Impact
+# ======
+# Many insecure service clients are used as troubleshooting tools and in
+# testing environments. Uninstalling them can inhibit capability to test
+# and troubleshoot. If they are required it is advisable to remove the
+# clients after use to prevent accidental or intentional misuse.
+#
+# NOTE
+# ====
+# It is not possible to remove rsh-client by means of SaltStack because
+# of the way SaltStack checks that package was really removed. 'rsh-client'
+# is "provided" by openssh-client package, and SaltStack thinks that
+# it is the same as 'rsh-client is installed'. So each time we try to
+# remove 'rsh-client' on a system where 'openssh-client' is installed
+# (that's almost every system), we got state failure.
+# This was fixed in upstream SaltStack in 2018, not sure where we start using
+# this version. Until that moment 'rsh-client' should remain unmanaged.
+#
+parameters:
+ linux:
+ system:
+ package:
+# rsh-client:
+# version: removed
+ rsh-redone-client:
+ version: removed
+
diff --git a/metadata/service/system/cis/cis-2-3-3.yml b/metadata/service/system/cis/cis-2-3-3.yml
new file mode 100644
index 0000000..859754b
--- /dev/null
+++ b/metadata/service/system/cis/cis-2-3-3.yml
@@ -0,0 +1,39 @@
+# 2.3.3 Ensure talk client is not installed
+#
+# Description
+# ===========
+# The talk software makes it possible for users to send and receive messages
+# across systems through a terminal session. The talk client, which allows
+# initialization of talk sessions, is installed by default.
+#
+# Rationale
+# =========
+# The software presents a security risk as it uses unencrypted protocols
+# for communication.
+#
+# Audit
+# =====
+# Run the following command and verify talk is not installed:
+#
+# dpkg -s talk
+#
+# Remediation
+# ===========
+# Run the following command to uninstall talk :
+#
+# apt-get remove talk
+#
+# Impact
+# ======
+# Many insecure service clients are used as troubleshooting tools and in
+# testing environments. Uninstalling them can inhibit capability to test
+# and troubleshoot. If they are required it is advisable to remove the clients
+# after use to prevent accidental or intentional misuse.
+#
+parameters:
+ linux:
+ system:
+ package:
+ talk:
+ version: removed
+
diff --git a/metadata/service/system/cis/cis-2-3-4.yml b/metadata/service/system/cis/cis-2-3-4.yml
new file mode 100644
index 0000000..34c8eb2
--- /dev/null
+++ b/metadata/service/system/cis/cis-2-3-4.yml
@@ -0,0 +1,40 @@
+# 2.3.4 Ensure telnet client is not installed
+#
+# Description
+# ===========
+# The telnet package contains the telnet client, which allows users to start
+# connections to other systems via the telnet protocol.
+#
+# Rationale
+# =========
+# The telnet protocol is insecure and unencrypted. The use of an unencrypted
+# transmission medium could allow an unauthorized user to steal credentials.
+# The ssh package provides an encrypted session and stronger security and is
+# included in most Linux distributions.
+#
+# Audit
+# =====
+# Run the following command and verify telnet is not installed:
+#
+# # dpkg -s telnet
+#
+# Remediation
+# ===========
+# Run the following command to uninstall telnet :
+#
+# # apt-get remove telnet
+#
+# Impact
+# ======
+# Many insecure service clients are used as troubleshooting tools and in
+# testing environments. Uninstalling them can inhibit capability to test and
+# troubleshoot. If they are required it is advisable to remove the clients
+# after use to prevent accidental or intentional misuse.
+#
+parameters:
+ linux:
+ system:
+ package:
+ telnet:
+ version: removed
+
diff --git a/metadata/service/system/cis/cis-3-5-1.yml b/metadata/service/system/cis/cis-3-5-1.yml
new file mode 100644
index 0000000..b232990
--- /dev/null
+++ b/metadata/service/system/cis/cis-3-5-1.yml
@@ -0,0 +1,38 @@
+# 3.5.2 Ensure DCCP is disabled
+#
+# Description
+# ===========
+# The Datagram Congestion Control Protocol (DCCP) is a transport layer protocol
+# that supports streaming media and telephony. DCCP provides a way to gain
+# access to congestion control, without having to do it at the application
+# layer, but does not provide in-sequence delivery.
+#
+# Rationale
+# =========
+# If the protocol is not required, it is recommended that the drivers not be
+# installed to reduce the potential attack surface.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v dccp
+# install /bin/true
+# # lsmod | grep dccp
+# <No output>
+#
+# Remediation
+# ===========
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install dccp /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ dccp:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-3-5-2.yml b/metadata/service/system/cis/cis-3-5-2.yml
new file mode 100644
index 0000000..0207eb9
--- /dev/null
+++ b/metadata/service/system/cis/cis-3-5-2.yml
@@ -0,0 +1,41 @@
+# 3.5.2 Ensure SCTP is disabled
+#
+# Description
+# ===========
+# The Stream Control Transmission Protocol (SCTP) is a transport layer
+# protocol used to support message oriented communication, with several
+# streams of messages in one connection. It serves a similar function as
+# TCP and UDP, incorporating features of both. It is message-oriented
+# like UDP, and ensures reliable in-sequence transport of messages with
+# congestion control like TCP.
+#
+# Rationale
+# =========
+# If the protocol is not being used, it is recommended that kernel module
+# not be loaded, disabling the service to reduce the potential attack surface.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v sctp
+# install /bin/true
+# # lsmod | grep sctp
+# <No output>
+#
+# Remediation
+# ===========
+#
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install sctp /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ sctp:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-3-5-3.yml b/metadata/service/system/cis/cis-3-5-3.yml
new file mode 100644
index 0000000..723de8b
--- /dev/null
+++ b/metadata/service/system/cis/cis-3-5-3.yml
@@ -0,0 +1,37 @@
+# 3.5.3 Ensure RDS is disabled
+#
+# Description
+# ===========
+# The Reliable Datagram Sockets (RDS) protocol is a transport layer protocol
+# designed to provide low-latency, high-bandwidth communications between
+# cluster nodes. It was developed by the Oracle Corporation.
+#
+# Rationale
+# =========
+# If the protocol is not being used, it is recommended that kernel module
+# not be loaded, disabling the service to reduce the potential attack surface.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v rds
+# install /bin/true
+# # lsmod | grep rds
+# <No output>
+#
+# Remediation
+# ===========
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install rds /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ rds:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-3-5-4.yml b/metadata/service/system/cis/cis-3-5-4.yml
new file mode 100644
index 0000000..6a4920c
--- /dev/null
+++ b/metadata/service/system/cis/cis-3-5-4.yml
@@ -0,0 +1,37 @@
+# 3.5.4 Ensure TIPC is disabled
+#
+# Description
+# ===========
+# The Transparent Inter-Process Communication (TIPC) protocol is designed
+# to provide communication between cluster nodes.
+#
+# Rationale
+# =========
+# If the protocol is not being used, it is recommended that kernel module
+# not be loaded, disabling the service to reduce the potential attack surface.
+#
+# Audit
+# =====
+# Run the following commands and verify the output is as indicated:
+#
+# # modprobe -n -v tipc
+# install /bin/true
+# # lsmod | grep tipc
+# <No output>
+#
+# Remediation
+# ===========
+#
+# Edit or create the file /etc/modprobe.d/CIS.conf and add the following line:
+#
+# install tipc /bin/true
+#
+parameters:
+ linux:
+ system:
+ kernel:
+ module:
+ tipc:
+ install:
+ command: /bin/true
+
diff --git a/metadata/service/system/cis/cis-5-4-1-1.yml b/metadata/service/system/cis/cis-5-4-1-1.yml
new file mode 100644
index 0000000..8b82466
--- /dev/null
+++ b/metadata/service/system/cis/cis-5-4-1-1.yml
@@ -0,0 +1,52 @@
+# CIS 5.4.1.1 Ensure password expiration is 90 days or less (Scored)
+#
+# Description
+# ===========
+# The PASS_MAX_DAYS parameter in /etc/login.defs allows an administrator to
+# force passwords to expire once they reach a defined age. It is recommended
+# that the PASS_MAX_DAYS parameter be set to less than or equal to 90 days.
+#
+# Rationale
+# =========
+# The window of opportunity for an attacker to leverage compromised credentials
+# or successfully compromise credentials via an online brute force attack is
+# limited by the age of the password. Therefore, reducing the maximum age of a
+# password also reduces an attacker's window of opportunity.
+#
+# Audit
+# =====
+# Run the following command and verify PASS_MAX_DAYS is 90 or less:
+#
+# # grep PASS_MAX_DAYS /etc/login.defs
+# PASS_MAX_DAYS 90
+#
+# Verify all users with a password have their maximum days between password
+# change set to 90 or less:
+#
+# # egrep ^[^:]+:[^\!*] /etc/shadow | cut -d: -f1
+# <list of users>
+# # chage --list <user>
+# Maximum number of days between password change: 90
+#
+# Remediation
+# ===========
+# Set the PASS_MAX_DAYS parameter to 90 in /etc/login.defs :
+#
+# PASS_MAX_DAYS 90
+#
+# Modify user parameters for all users with a password set to match:
+#
+# # chage --maxdays 90 <user>
+#
+# Notes
+# =====
+# You can also check this setting in /etc/shadow directly. The 5th field
+# should be 90 or less for all users with a password.
+#
+parameters:
+ linux:
+ system:
+ login_defs:
+ PASS_MAX_DAYS:
+ value: 90
+
diff --git a/metadata/service/system/cis/cis-5-4-1-2.yml b/metadata/service/system/cis/cis-5-4-1-2.yml
new file mode 100644
index 0000000..50543ca
--- /dev/null
+++ b/metadata/service/system/cis/cis-5-4-1-2.yml
@@ -0,0 +1,52 @@
+# CIS 5.4.1.2 Ensure minimum days between password changes is 7 or more (Scored)
+#
+# Description
+# ===========
+# The PASS_MIN_DAYS parameter in /etc/login.defs allows an administrator to
+# prevent users from changing their password until a minimum number of days
+# have passed since the last time the user changed their password. It is
+# recommended that PASS_MIN_DAYS parameter be set to 7 or more days.
+#
+# Rationale
+# =========
+# By restricting the frequency of password changes, an administrator can
+# prevent users from repeatedly changing their password in an attempt to
+# circumvent password reuse controls.
+#
+# Audit
+# =====
+# Run the following command and verify PASS_MIN_DAYS is 7 or more:
+#
+# # grep PASS_MIN_DAYS /etc/login.defs
+# PASS_MIN_DAYS 7
+#
+# Verify all users with a password have their minimum days between password
+# change set to 7 or more:
+#
+# # egrep ^[^:]+:[^\!*] /etc/shadow | cut -d: -f1
+# <list of users>
+# # chage --list <user>
+# Minimum number of days between password change: 7
+#
+# Remediation
+# ===========
+# Set the PASS_MIN_DAYS parameter to 7 in /etc/login.defs :
+#
+# PASS_MIN_DAYS 7
+#
+# Modify user parameters for all users with a password set to match:
+#
+# # chage --mindays 7 <user>
+#
+# Notes
+# =====
+# You can also check this setting in /etc/shadow directly. The 5th field
+# should be 7 or more for all users with a password.
+#
+parameters:
+ linux:
+ system:
+ login_defs:
+ PASS_MIN_DAYS:
+ value: 7
+
diff --git a/metadata/service/system/cis/cis-5-4-1-3.yml b/metadata/service/system/cis/cis-5-4-1-3.yml
new file mode 100644
index 0000000..3567f2a
--- /dev/null
+++ b/metadata/service/system/cis/cis-5-4-1-3.yml
@@ -0,0 +1,52 @@
+# CIS 5.4.1.3 Ensure password expiration warning days is 7 or more (Scored)
+#
+# Description
+# ===========
+# The PASS_WARN_AGE parameter in /etc/login.defs allows an administrator to
+# notify users that their password will expire in a defined number of days.
+# It is recommended that the PASS_WARN_AGE parameter be set to 7 or more days.
+#
+# Rationale
+# =========
+# Providing an advance warning that a password will be expiring gives users
+# time to think of a secure password. Users caught unaware may choose a simple
+# password or write it down where it may be discovered.
+#
+# Audit
+# =====
+# Run the following command and verify PASS_WARN_AGE is 7 or more:
+#
+# # grep PASS_WARN_AGE /etc/login.defs
+# PASS_WARN_AGE 7
+#
+# Verify all users with a password have their number of days of warning before
+# password expires set to 7 or more:
+#
+# # egrep ^[^:]+:[^\!*] /etc/shadow | cut -d: -f1
+# <list of users>
+# # chage --list <user>
+# Number of days of warning before password expires: 7
+#
+# Remediation
+# ===========
+#
+# Set the PASS_WARN_AGE parameter to 7 in /etc/login.defs :
+#
+# PASS_WARN_AGE 7
+#
+# Modify user parameters for all users with a password set to match:
+#
+# # chage --warndays 7 <user>
+#
+# Notes
+# =====
+# You can also check this setting in /etc/shadow directly. The 6th field
+# should be 7 or more for all users with a password.
+#
+parameters:
+ linux:
+ system:
+ login_defs:
+ PASS_WARN_AGE:
+ value: 7
+
diff --git a/metadata/service/system/cis/cis-5-4-4.yml b/metadata/service/system/cis/cis-5-4-4.yml
new file mode 100644
index 0000000..639babc
--- /dev/null
+++ b/metadata/service/system/cis/cis-5-4-4.yml
@@ -0,0 +1,57 @@
+# CIS 5.4.4 Ensure default user umask is 027 or more restrictive (Scored)
+#
+# Description
+# ===========
+# The default umask determines the permissions of files created by users.
+# The user creating the file has the discretion of making their files and
+# directories readable by others via the chmod command. Users who wish to
+# allow their files and directories to be readable by others by default may
+# choose a different default umask by inserting the umask command into the
+# standard shell configuration files ( .profile , .bashrc , etc.) in their
+# home directories.
+#
+# Rationale
+# =========
+# Setting a very secure default value for umask ensures that users make a
+# conscious choice about their file permissions. A default umask setting of
+# 077 causes files and directories created by users to not be readable by
+# any other user on the system. A umask of 027 would make files and
+# directories readable by users in the same Unix group, while a umask of 022
+# would make files readable by every user on the system.
+#
+# Audit
+# =====
+# Run the following commands and verify all umask lines returned are 027 or
+# more restrictive.
+#
+# # grep "^umask" /etc/bash.bashrc
+# umask 027
+# # grep "^umask" /etc/profile
+# umask 027
+#
+# Remediation
+# ===========
+# Edit the /etc/bash.bashrc and /etc/profile files (and the appropriate files
+# for any other shell supported on your system) and add or edit any umask
+# parameters as follows:
+#
+# umask 027
+#
+# Notes
+# =====
+# The audit and remediation in this recommendation apply to bash and shell.
+# If other shells are supported on the system, it is recommended that their
+# configuration files also are checked.
+#
+# Other methods of setting a default user umask exist however the shell
+# configuration files are the last run and will override other settings if
+# they exist therefore our recommendation is to configure in the shell
+# configuration files. If other methods are in use in your environment they
+# should be audited and the shell configs should be verified to not override.
+#
+parameters:
+ linux:
+ system:
+ shell:
+ umask: "027"
+
diff --git a/metadata/service/system/cis/cis-6-1-2.yml b/metadata/service/system/cis/cis-6-1-2.yml
new file mode 100644
index 0000000..481c2df
--- /dev/null
+++ b/metadata/service/system/cis/cis-6-1-2.yml
@@ -0,0 +1,38 @@
+# CIS 6.1.2 Ensure permissions on /etc/passwd are configured
+#
+# Description
+# ===========
+# The /etc/passwd file contains user account information that is used by
+# many system utilities and therefore must be readable for these utilities
+# to operate.
+#
+# Rationale
+# =========
+# It is critical to ensure that the /etc/passwd file is protected from
+# unauthorized write access. Although it is protected by default, the file
+# permissions could be changed either inadvertently or through malicious actions.
+#
+# Audit
+# =====
+# Run the following command and verify Uid and Gid are both 0/root and
+# Access is 644 :
+#
+# # stat /etc/passwd
+# Access: (0644/-rw-r--r--) Uid: (0/root) Gid: (0/root)
+#
+# Remediation
+# ===========
+# Run the following command to set permissions on /etc/passwd :
+#
+# # chown root:root /etc/passwd
+# # chmod 644 /etc/passwd
+#
+parameters:
+ linux:
+ system:
+ file:
+ /etc/passwd:
+ user: 'root'
+ group: 'root'
+ mode: '0644'
+
diff --git a/metadata/service/system/cis/cis-6-1-3.yml b/metadata/service/system/cis/cis-6-1-3.yml
new file mode 100644
index 0000000..7bcd373
--- /dev/null
+++ b/metadata/service/system/cis/cis-6-1-3.yml
@@ -0,0 +1,39 @@
+# CIS 6.1.3 Ensure permissions on /etc/shadow are configured
+#
+# Description
+# ===========
+# The /etc/shadow file is used to store the information about user accounts
+# that is critical to the security of those accounts, such as the hashed
+# password and other security information.
+#
+# Rationale
+# =========
+# If attackers can gain read access to the /etc/shadow file, they can easily
+# run a password cracking program against the hashed password to break it.
+# Other security information that is stored in the /etc/shadow file (such
+# as expiration) could also be useful to subvert the user accounts.
+#
+# Audit
+# =====
+# Run the following command and verify Uid is 0/root , Gid is <gid>/shadow ,
+# and Access is 640 or more restrictive:
+#
+# # stat /etc/shadow
+# Access: (0640/-rw-r-----) Uid: (0/root) Gid: (42/shadow)
+#
+# Remediation
+# ===========
+# Run the one following commands to set permissions on /etc/shadow :
+#
+# # chown root:shadow /etc/shadow
+# # chmod o-rwx,g-wx /etc/shadow
+#
+parameters:
+ linux:
+ system:
+ file:
+ /etc/shadow:
+ user: 'root'
+ group: 'shadow'
+ mode: '0640'
+
diff --git a/metadata/service/system/cis/cis-6-1-4.yml b/metadata/service/system/cis/cis-6-1-4.yml
new file mode 100644
index 0000000..d5b2ffd
--- /dev/null
+++ b/metadata/service/system/cis/cis-6-1-4.yml
@@ -0,0 +1,38 @@
+# CIS 6.1.4 Ensure permissions on /etc/group are configured
+#
+# Description
+# ===========
+# The /etc/group file contains a list of all the valid groups defined in the
+# system. The command below allows read/write access for root and read access
+# for everyone else.
+#
+# Rationale
+# =========
+# The /etc/group file needs to be protected from unauthorized changes by
+# non-privileged users, but needs to be readable as this information is used
+# with many non-privileged programs.
+#
+# Audit
+# =====
+# Run the following command and verify Uid and Gid are both 0/root and
+# Access is 644 :
+#
+# # stat /etc/group
+# Access: (0644/-rw-r--r--) Uid: (0/root) Gid: (0/root)
+#
+# Remediation
+# ===========
+# Run the following command to set permissions on /etc/group :
+#
+# # chown root:root /etc/group
+# # chmod 644 /etc/group
+#
+parameters:
+ linux:
+ system:
+ file:
+ /etc/group:
+ user: 'root'
+ group: 'root'
+ mode: '0644'
+
diff --git a/metadata/service/system/cis/cis-6-1-5.yml b/metadata/service/system/cis/cis-6-1-5.yml
new file mode 100644
index 0000000..87ef05a
--- /dev/null
+++ b/metadata/service/system/cis/cis-6-1-5.yml
@@ -0,0 +1,39 @@
+# CIS 6.1.5 Ensure permissions on /etc/gshadow are configured
+#
+# Description
+# ===========
+# The /etc/gshadow file is used to store the information about groups that
+# is critical to the security of those accounts, such as the hashed password
+# and other security information.
+#
+# Rationale
+# =========
+# If attackers can gain read access to the /etc/gshadow file, they can easily
+# run a password cracking program against the hashed password to break it.
+# Other security information that is stored in the /etc/gshadow file (such as
+# group administrators) could also be useful to subvert the group.
+#
+# Audit
+# =====
+# Run the following command and verify verify Uid is 0/root ,
+# Gid is <gid>/shadow , and Access is 640 or more restrictive:
+#
+# # stat /etc/gshadow
+# Access: (0640/-rw-r-----) Uid: (0/root) Gid: (42/shadow)
+#
+# Remediation
+# ===========
+# Run the following commands to set permissions on /etc/gshadow :
+#
+# # chown root:shadow /etc/gshadow
+# # chmod o-rwx,g-rw /etc/gshadow
+#
+parameters:
+ linux:
+ system:
+ file:
+ /etc/gshadow:
+ user: 'root'
+ group: 'shadow'
+ mode: '0640'
+
diff --git a/metadata/service/system/cis/cis-6-1-6.yml b/metadata/service/system/cis/cis-6-1-6.yml
new file mode 100644
index 0000000..0cd4b9f
--- /dev/null
+++ b/metadata/service/system/cis/cis-6-1-6.yml
@@ -0,0 +1,36 @@
+# CIS 6.1.6 Ensure permissions on /etc/passwd- are configured
+#
+# Description
+# ===========
+# The /etc/passwd- file contains backup user account information.
+#
+# Rationale
+# =========
+# It is critical to ensure that the /etc/passwd- file is protected from
+# unauthorized access. Although it is protected by default, the file
+# permissions could be changed either inadvertently or through malicious actions.
+#
+# Audit
+# =====
+# Run the following command and verify Uid and Gid are both 0/root and
+# Access is 600 or more restrictive:
+#
+# # stat /etc/passwd-
+# Access: (0600/-rw-------) Uid: (0/root) Gid: (0/root)
+#
+# Remediation
+# ===========
+# Run the following command to set permissions on /etc/passwd- :
+#
+# # chown root:root /etc/passwd-
+# # chmod 600 /etc/passwd-
+#
+parameters:
+ linux:
+ system:
+ file:
+ /etc/passwd-:
+ user: 'root'
+ group: 'root'
+ mode: '0600'
+
diff --git a/metadata/service/system/cis/cis-6-1-7.yml b/metadata/service/system/cis/cis-6-1-7.yml
new file mode 100644
index 0000000..4918e6b
--- /dev/null
+++ b/metadata/service/system/cis/cis-6-1-7.yml
@@ -0,0 +1,38 @@
+# CIS 6.1.7 Ensure permissions on /etc/shadow- are configured
+#
+# Description
+# ===========
+# The /etc/shadow- file is used to store backup information about user
+# accounts that is critical to the security of those accounts, such as the
+# hashed password and other security information.
+#
+# Rationale
+# =========
+# It is critical to ensure that the /etc/shadow- file is protected from
+# unauthorized access. Although it is protected by default, the file
+# permissions could be changed either inadvertently or through malicious actions.
+#
+# Audit
+# =====
+# Run the following command and verify Uid and Gid are both 0/root and
+# Access is 600 or more restrictive:
+#
+# # stat /etc/shadow-
+# Access: (0600/-rw-------) Uid: (0/root) Gid: (0/root)
+#
+# Remediation
+# ===========
+# Run the following command to set permissions on /etc/shadow- :
+#
+# # chown root:root /etc/shadow-
+# # chmod 600 /etc/shadow-
+#
+parameters:
+ linux:
+ system:
+ file:
+ /etc/shadow-:
+ user: 'root'
+ group: 'root'
+ mode: '0600'
+
diff --git a/metadata/service/system/cis/cis-6-1-8.yml b/metadata/service/system/cis/cis-6-1-8.yml
new file mode 100644
index 0000000..eb7bb16
--- /dev/null
+++ b/metadata/service/system/cis/cis-6-1-8.yml
@@ -0,0 +1,37 @@
+# CIS 6.1.8 Ensure permissions on /etc/group- are configured
+#
+# Description
+# ===========
+# The /etc/group- file contains a backup list of all the valid groups defined
+# in the system.
+#
+# Rationale
+# =========
+# It is critical to ensure that the /etc/group- file is protected from
+# unauthorized access. Although it is protected by default, the file
+# permissions could be changed either inadvertently or through malicious actions.
+#
+# Audit
+# =====
+# Run the following command and verify Uid and Gid are both 0/root and
+# Access is 600 or more restrictive:
+#
+# # stat /etc/group-
+# Access: (0600/-rw-------) Uid: (0/root) Gid: (0/root)
+#
+# Remediation
+# ===========
+# Run the following command to set permissions on /etc/group- :
+#
+# # chown root:root /etc/group-
+# # chmod 600 /etc/group-
+#
+parameters:
+ linux:
+ system:
+ file:
+ /etc/group-:
+ user: 'root'
+ group: 'root'
+ mode: '0600'
+
diff --git a/metadata/service/system/cis/cis-6-1-9.yml b/metadata/service/system/cis/cis-6-1-9.yml
new file mode 100644
index 0000000..7acba2f
--- /dev/null
+++ b/metadata/service/system/cis/cis-6-1-9.yml
@@ -0,0 +1,38 @@
+# CIS 6.1.9 Ensure permissions on /etc/gshadow- are configured
+#
+# Description
+# ===========
+# The /etc/gshadow- file is used to store backup information about groups
+# that is critical to the security of those accounts, such as the hashed
+# password and other security information.
+#
+# Rationale
+# =========
+# It is critical to ensure that the /etc/gshadow- file is protected from
+# unauthorized access. Although it is protected by default, the file
+# permissions could be changed either inadvertently or through malicious actions.
+#
+# Audit
+# =====
+# Run the following command and verify Uid and Gid are both 0/root and
+# Access is 600 or more restrictive:
+#
+# # stat /etc/gshadow-
+# Access: (0600/-rw-------) Uid: (0/root) Gid: (0/root)
+#
+# Remediation
+# ===========
+# Run the following command to set permissions on /etc/gshadow- :
+#
+# # chown root:root /etc/gshadow-
+# # chmod 600 /etc/gshadow-
+#
+parameters:
+ linux:
+ system:
+ file:
+ /etc/gshadow-:
+ user: 'root'
+ group: 'root'
+ mode: '0600'
+
diff --git a/metadata/service/system/cis/init.yml b/metadata/service/system/cis/init.yml
index a6664f1..0c2626d 100644
--- a/metadata/service/system/cis/init.yml
+++ b/metadata/service/system/cis/init.yml
@@ -1,6 +1,21 @@
classes:
+- service.linux.system.cis.cis-1-1-1-1
+- service.linux.system.cis.cis-1-1-1-2
+- service.linux.system.cis.cis-1-1-1-3
+- service.linux.system.cis.cis-1-1-1-4
+- service.linux.system.cis.cis-1-1-1-5
+- service.linux.system.cis.cis-1-1-1-6
+- service.linux.system.cis.cis-1-1-1-7
+- service.linux.system.cis.cis-1-1-1-8
+- service.linux.system.cis.cis-1-1-14_15_16
+- service.linux.system.cis.cis-1-1-21
- service.linux.system.cis.cis-1-5-1
- service.linux.system.cis.cis-1-5-3
+- service.linux.system.cis.cis-1-5-4
+- service.linux.system.cis.cis-2-3-1
+- service.linux.system.cis.cis-2-3-2
+- service.linux.system.cis.cis-2-3-3
+- service.linux.system.cis.cis-2-3-4
- service.linux.system.cis.cis-3-1-2
- service.linux.system.cis.cis-3-2-1
- service.linux.system.cis.cis-3-2-2
@@ -12,3 +27,19 @@
- service.linux.system.cis.cis-3-2-8
# Temp. disable PROD-22520
#- service.linux.system.cis.cis-3-3-3
+- service.linux.system.cis.cis-3-5-1
+- service.linux.system.cis.cis-3-5-2
+- service.linux.system.cis.cis-3-5-3
+- service.linux.system.cis.cis-3-5-4
+- service.linux.system.cis.cis-5-4-1-1
+- service.linux.system.cis.cis-5-4-1-2
+- service.linux.system.cis.cis-5-4-1-3
+- service.linux.system.cis.cis-5-4-4
+- service.linux.system.cis.cis-6-1-2
+- service.linux.system.cis.cis-6-1-3
+- service.linux.system.cis.cis-6-1-4
+- service.linux.system.cis.cis-6-1-5
+- service.linux.system.cis.cis-6-1-6
+- service.linux.system.cis.cis-6-1-7
+- service.linux.system.cis.cis-6-1-8
+- service.linux.system.cis.cis-6-1-9
diff --git a/tests/pillar/system.sls b/tests/pillar/system.sls
index 555a0cd..43fc65c 100644
--- a/tests/pillar/system.sls
+++ b/tests/pillar/system.sls
@@ -5,6 +5,20 @@
fqdn: linux.ci.local
system:
enabled: true
+ at:
+ enabled: true
+ user:
+ root:
+ enabled: true
+ testuser:
+ enabled: true
+ cron:
+ enabled: true
+ user:
+ root:
+ enabled: true
+ testuser:
+ enabled: true
cluster: default
name: linux
domain: ci.local
@@ -85,6 +99,7 @@
subjects:
- '@group1'
sysfs:
+ enable_apply: true
scheduler:
block/sda/queue/scheduler: deadline
power:
@@ -113,6 +128,7 @@
enabled: true
home: /root
name: root
+ maxdays: 365
testuser:
enabled: true
name: testuser
@@ -187,6 +203,22 @@
proxy:
enabled: true
https: https://127.0.5.1:443
+ saltstack:
+ source: "deb [arch=amd64] http://repo.saltstack.com/apt/ubuntu/16.04/amd64/2017.7/ xenial main"
+ key_url: "http://repo.saltstack.com/apt/ubuntu/16.04/amd64/2017.7/SALTSTACK-GPG-KEY.pub"
+ architectures: amd64
+ clean_file: true
+ pinning:
+ 10:
+ enabled: true
+ pin: 'release o=SaltStack'
+ priority: 50
+ package: 'libsodium18'
+ 20:
+ enabled: true
+ pin: 'release o=SaltStack'
+ priority: 1100
+ package: '*'
opencontrail:
source: "deb http://ppa.launchpad.net/tcpcloud/contrail-3.0/ubuntu xenial main"
keyid: E79EE90C
@@ -393,6 +425,12 @@
- .local
LANG: C
LC_ALL: C
+ login_defs:
+ PASS_MAX_DAYS:
+ value: 99
+ shell:
+ umask: '027'
+ timeout: 900
profile:
vi_flavors.sh: |
export PAGER=view