Browse Source

Merge pull request #767 from abhishek-sa1/control_plane_security

Issue #766: Security Features in Management Station
Sujit Jadhav 3 years ago
parent
commit
147cbf4b43

+ 24 - 1
control_plane/input_params/security_vars.yml

@@ -20,4 +20,27 @@ domain_name: "omnia.test"
 # the authority to authenticate a user, host or service.
 # the authority to authenticate a user, host or service.
 # A realm name is often, but not always the upper case version of the name of the
 # A realm name is often, but not always the upper case version of the name of the
 # DNS domain over which it presides
 # DNS domain over which it presides
-realm_name: "OMNIA.TEST"
+realm_name: "OMNIA.TEST"
+
+# Maximum number of consecutive failures before lockout
+# The default value of this variable can't be changed
+# Default: 3
+max_failures: 3
+
+# Period (in seconds) after which the number of failed login attempts is reset
+# Default: 60
+# Min: 30
+# Max: 60
+failure_reset_interval: 60
+
+# Period (in seconds) for which users are locked out 
+# Default: 10
+# Min: 5
+# Max: 10
+lockout_duration: 10
+
+# User sessions that have been idle for a specific period can be ended automatically
+# This variable sets session timeout to 3 minutes (180 seconds) by default
+# Min: 90
+# Max: 180
+session_timeout: 180

+ 1 - 1
control_plane/roles/control_plane_common/tasks/fetch_base_inputs.yml

@@ -56,7 +56,7 @@
 - name: Calculate max lease time
 - name: Calculate max lease time
   set_fact:
   set_fact:
     max_lease_time: "{{ default_lease_time|int + 10000 }}"
     max_lease_time: "{{ default_lease_time|int + 10000 }}"
-  tags: [ init, pxe, network-device, network-ib ]
+  tags: init
 
 
 - name: Validate infiniband base_vars are not empty
 - name: Validate infiniband base_vars are not empty
   assert:
   assert:

+ 39 - 1
control_plane/roles/control_plane_common/tasks/fetch_security_inputs.yml

@@ -18,7 +18,7 @@
   no_log: true
   no_log: true
   tags: init
   tags: init
 
 
-- name: Validate input parameters of base_vars are not empty
+- name: Validate input parameters of security vars are not empty
   fail:
   fail:
     msg: "{{ input_security_failure_msg }}"
     msg: "{{ input_security_failure_msg }}"
   register: input_base_check
   register: input_base_check
@@ -43,3 +43,41 @@
     success_msg: "{{ realm_success_msg }}"
     success_msg: "{{ realm_success_msg }}"
     fail_msg: "{{ realm_fail_msg }}"
     fail_msg: "{{ realm_fail_msg }}"
   tags: [ validate, security ]
   tags: [ validate, security ]
+
+- name: Validate max_failures
+  assert:
+    that:
+      - max_failures | int == max_failures_default_value
+    success_msg: "{{ max_failures_success_msg }}"
+    fail_msg: "{{ max_failures_fail_msg }}"
+  tags: [ validate, security ]
+
+- name: Validate failure_reset_interval
+  assert:
+    that:
+      - failure_reset_interval | int
+      - failure_reset_interval | int <= failure_reset_interval_max_value
+      - failure_reset_interval | int >= failure_reset_interval_min_value
+    success_msg: "{{ failure_reset_interval_success_msg }}"
+    fail_msg: "{{ failure_reset_interval_fail_msg }}"
+  tags: [ validate, security ]
+
+- name: Validate lockout_duration
+  assert:
+    that:
+      - lockout_duration | int
+      - lockout_duration | int <= lockout_duration_max_value
+      - lockout_duration | int >= lockout_duration_min_value
+    success_msg: "{{ lockout_duration_success_msg }}"
+    fail_msg: "{{ lockout_duration_fail_msg }}"
+  tags: [ validate, security ]
+
+- name: Validate session_timeout
+  assert:
+    that:
+      - session_timeout | int
+      - session_timeout | int <= session_timeout_max_value
+      - session_timeout | int >= session_timeout_min_value
+    success_msg: "{{ session_timeout_success_msg }}"
+    fail_msg: "{{ session_timeout_fail_msg }}"
+  tags: [ validate, security ]

+ 15 - 0
control_plane/roles/control_plane_common/vars/main.yml

@@ -234,6 +234,21 @@ dom_name_success_msg: "domain name successfully validated"
 dom_name_fail_msg: "Failed. Incorrect format provided for domain name in security_vars.yml"
 dom_name_fail_msg: "Failed. Incorrect format provided for domain name in security_vars.yml"
 realm_success_msg: "realm_name successfully validated"
 realm_success_msg: "realm_name successfully validated"
 realm_fail_msg: "Failed. Incorrect realm_name format in security_vars.yml"
 realm_fail_msg: "Failed. Incorrect realm_name format in security_vars.yml"
+max_failures_success_msg: "max_failures successfully validated"
+max_failures_fail_msg: "Failed. Incorrect max_failures value in security_vars.yml"
+failure_reset_interval_success_msg: "failure_reset_interval successfully validated"
+failure_reset_interval_fail_msg: "Failed. Incorrect failure_reset_interval value in security_vars.yml"
+lockout_duration_success_msg: "lockout_duration successfully validated"
+lockout_duration_fail_msg: "Failed. Incorrect lockout_duration value in security_vars.yml"
+session_timeout_success_msg: "session_timeout successfully validated"
+session_timeout_fail_msg: "Failed. Incorrect session_timeout value in security_vars.yml"
+max_failures_default_value: 3
+failure_reset_interval_min_value: 30
+failure_reset_interval_max_value: 60
+lockout_duration_min_value: 5
+lockout_duration_max_value: 10
+session_timeout_min_value: 90
+session_timeout_max_value: 180
 
 
 # Usage: validate_idrac_vars.yml
 # Usage: validate_idrac_vars.yml
 idrac_input_filename: input_params/idrac_vars.yml
 idrac_input_filename: input_params/idrac_vars.yml

+ 4 - 8
control_plane/roles/control_plane_security/tasks/update_package.yml

@@ -13,11 +13,7 @@
 #  limitations under the License.
 #  limitations under the License.
 ---
 ---
 
 
-- name: Update nss package to install ipa server/client
-  command: yum update nss -y
-  changed_when: false
-  args:
-    warn: false
-  when:
-    - ( ansible_distribution | lower == os_centos )
-    - ( ansible_distribution_version < os_version )
+- name: Restart sshd
+  ansible.builtin.systemd:
+    name: sshd
+    state: restarted

+ 64 - 0
control_plane/roles/control_plane_security/tasks/check_prerequisites.yml

@@ -0,0 +1,64 @@
+#  Copyright 2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+---
+
+- name: Initialize freeipa_status
+  set_fact:
+    freeipa_status: false
+    
+- name: Fetch hostname
+  command: hostname
+  register: new_serv_hostname
+  changed_when: false
+
+- name: Set fact for server hostname
+  set_fact:
+    server_hostname_ms: "{{ new_serv_hostname.stdout }}"
+
+- name: Create files directory
+  file:
+    path: "{{ role_path }}/files"
+    state: directory
+    mode: "{{ file_mode }}"
+    
+- name: Save the hostname
+  copy:
+    dest: "{{ server_file }}"
+    content: |
+      ipaddress: "{{ public_ip }}"
+      server_hostname: "{{ server_hostname_ms }}"
+      server_domain: "{{ domain_name }}"
+    mode: "{{ file_mode }}"
+    
+- name: Check freeipa ui accessible or not
+  uri:
+    url: "https://{{ server_hostname_ms }}"
+    status_code: "{{ return_status }}"
+    return_content: true
+  register: freeipa_ui_status
+  failed_when: false
+
+- name: Check freeipa admin authentication
+  shell: set -o pipefail && echo $'{{ ipa_admin_password }}' | kinit {{ ipa_admin_username }}
+  register: freeipa_authentication
+  no_log: true
+  changed_when: false
+  failed_when: false
+ 
+- name: Modify freeipa_status
+  set_fact:
+    freeipa_status: true
+  when:
+    - freeipa_authentication.rc == 0
+    - freeipa_ui_status.status == return_status

+ 4 - 4
control_plane/roles/control_plane_security/tasks/enable_dnf_module.yml

@@ -13,9 +13,9 @@
 #  limitations under the License.
 #  limitations under the License.
 ---
 ---
 
 
-- name: Enable module idm in Rocky or Centos >= 8.0
+- name: Enable module idm in Rocky or CentOS
   command: dnf module enable idm:DL1 -y
   command: dnf module enable idm:DL1 -y
+  changed_when: false
   when:
   when:
-    - ( ansible_distribution | lower == os_centos ) or
-      ( ansible_distribution | lower == os_rocky )
-    - ( ansible_distribution_version >= os_version )
+    - ( os_supported_centos in mgmt_os ) or
+      ( os_supported_rocky in mgmt_os )

+ 4 - 29
control_plane/roles/control_plane_security/tasks/install_ipa_server.yml

@@ -13,30 +13,6 @@
 #  limitations under the License.
 #  limitations under the License.
 ---
 ---
 
 
-- name: Fetch hostname
-  command: hostname
-  register: new_serv_hostname
-  changed_when: false
-
-- name: Set fact for server hostname
-  set_fact:
-    server_hostname_ms: "{{ new_serv_hostname.stdout }}"
-
-- name: Save the hostname
-  copy:
-    dest: "{{ server_file }}"
-    content: |
-      ipaddress: "{{ hostvars['localhost']['ansible_default_ipv4']['address'] }}"
-      server_hostname: "{{ server_hostname_ms }}"
-      server_domain: "{{ domain_name }}"
-    owner: root
-    mode: "{{ file_mode }}"
-
-- name: Uninstall server if it is already installed
-  command: ipa-server-install --uninstall -U
-  changed_when: false
-  failed_when: false
-
 - name: Install ipa server in CentOS > 8 or Rocky 8.4
 - name: Install ipa server in CentOS > 8 or Rocky 8.4
   command: >-
   command: >-
     ipa-server-install -n '{{ domain_name }}' --hostname='{{ server_hostname_ms }}' -a '{{ ipa_admin_password }}'
     ipa-server-install -n '{{ domain_name }}' --hostname='{{ server_hostname_ms }}' -a '{{ ipa_admin_password }}'
@@ -44,12 +20,11 @@
   changed_when: true
   changed_when: true
   no_log: true
   no_log: true
   when:
   when:
-    - ( ansible_distribution | lower == os_centos ) or
-      ( ansible_distribution | lower == os_rocky )
-    - ( ansible_distribution_version >= os_version )
+    - ( os_supported_centos in mgmt_os ) or
+      ( os_supported_rocky in mgmt_os )
 
 
 - name: Authenticate as admin
 - name: Authenticate as admin
-  shell: set -o pipefail && echo $'{{ ipa_admin_password }}' | kinit admin
+  shell: set -o pipefail && echo $'{{ ipa_admin_password }}' | kinit {{ ipa_admin_username }}
   no_log: true
   no_log: true
   changed_when: false
   changed_when: false
 
 
@@ -58,4 +33,4 @@
     src: "{{ temp_resolv_conf_path }}"
     src: "{{ temp_resolv_conf_path }}"
     dest: "{{ resolv_conf_path }}"
     dest: "{{ resolv_conf_path }}"
     mode: "{{ file_mode }}"
     mode: "{{ file_mode }}"
-    remote_src: yes
+    remote_src: yes

+ 8 - 8
control_plane/roles/control_plane_security/tasks/install_packages.yml

@@ -23,19 +23,19 @@
   copy:
   copy:
     src: "{{ resolv_conf_path }}"
     src: "{{ resolv_conf_path }}"
     dest: "{{ temp_resolv_conf_path }}"
     dest: "{{ temp_resolv_conf_path }}"
-    mode: "{{ resolv_file_mode }}"
+    mode: "{{ file_mode }}"
     remote_src: yes
     remote_src: yes
 
 
 - name: Add the domain name in /etc/resolv.conf
 - name: Add the domain name in /etc/resolv.conf
-  replace:
+  lineinfile:
     path: "{{ temp_resolv_conf_path }}"
     path: "{{ temp_resolv_conf_path }}"
-    regexp: "search"
-    replace: "search {{ domain_name }}"
+    regexp: "^search"
+    line: "search {{ domain_name }}"
   register: replace_output
   register: replace_output
 
 
 - name: Add the domain name in /etc/resolv.conf when there is no domain name
 - name: Add the domain name in /etc/resolv.conf when there is no domain name
-  replace:
+  lineinfile:
     path: "{{ temp_resolv_conf_path }}"
     path: "{{ temp_resolv_conf_path }}"
-    regexp: "# Generated by NetworkManager"
-    replace: "# Generated by NetworkManager\nsearch {{ domain_name }}"
-  when: replace_output.msg | length == 0
+    insertafter: "^# Generated by NetworkManager"
+    line: "search {{ domain_name }}"
+  when: replace_output.msg | length == 0

+ 46 - 0
control_plane/roles/control_plane_security/tasks/ipa_configuration.yml

@@ -0,0 +1,46 @@
+#  Copyright 2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+---
+
+- name: Modify the freeipa global password policy
+  community.general.ipa_pwpolicy:
+    maxfailcount: "{{ max_failures }}"
+    failinterval: "{{ failure_reset_interval }}"
+    lockouttime: "{{ lockout_duration }}"
+    ipa_host: "{{ server_hostname_ms }}"
+    ipa_user: "{{ ipa_admin_username }}"
+    ipa_pass: "{{ ipa_admin_password }}"
+
+- name: Create sysadmin group
+  community.general.ipa_group:
+    name: "{{ sysadmin_user_group }}"
+    description: "{{ sysadmin_group_description }}"
+    state: present
+    ipa_host: "{{ server_hostname_ms }}"
+    ipa_user: "{{ ipa_admin_username }}"
+    ipa_pass: "{{ ipa_admin_password }}"
+    
+- name: Create sysadmin_sudo rule
+  community.general.ipa_sudorule:
+    name: "{{ sysadmin_sudo_rule }}"
+    description: "{{ sysadmin_sudo_rule_description }}"
+    cmdcategory: all        
+    hostcategory: all
+    runasgroupcategory: all
+    runasusercategory: all
+    usergroup:
+      - "{{ sysadmin_user_group }}"
+    ipa_host: "{{ server_hostname_ms }}"
+    ipa_user: "{{ ipa_admin_username }}"
+    ipa_pass: "{{ ipa_admin_password }}"

+ 23 - 20
control_plane/roles/control_plane_security/tasks/main.yml

@@ -13,27 +13,30 @@
 #  limitations under the License.
 #  limitations under the License.
 ---
 ---
 
 
-- name: Add ports of manager and login node to firewall
-  include_tasks: firewall_settings.yml
-  when:
-    - enable_security_support
+- block:
+    - name: Check freeipa installed or not
+      include_tasks: check_prerequisites.yml
 
 
-- name: Enable module idm in Rocky or Centos >= 8.0
-  include_tasks: enable_dnf_module.yml
-  when:
-    - enable_security_support
+    - block:
+        - name: Add ports of manager and login node to firewall
+          include_tasks: firewall_settings.yml
 
 
-- name: Update Packages
-  include_tasks: update_package.yml
-  when:
-    - enable_security_support
+        - name: Enable module idm in Rocky or Centos >= 8.0
+          include_tasks: enable_dnf_module.yml
 
 
-- name: Install required packages
-  include_tasks: install_packages.yml
-  when:
-    - enable_security_support
+        - name: Install required packages
+          include_tasks: install_packages.yml
+
+        - name: Install FreeIPA server
+          include_tasks: install_ipa_server.yml
+      when: not freeipa_status
+    
+    - name: FreeIPA configuration
+      include_tasks: ipa_configuration.yml
 
 
-- name: Install free-ipa server
-  include_tasks: install_ipa_server.yml
-  when:
-    - enable_security_support
+    - name: Session timeout configuration
+      include_tasks: session_timeout.yml
+  when: 
+    - enable_security_support
+    - ( os_supported_centos in mgmt_os ) or
+      ( os_supported_rocky in mgmt_os )

+ 26 - 0
control_plane/roles/control_plane_security/tasks/session_timeout.yml

@@ -0,0 +1,26 @@
+#  Copyright 2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+---
+
+- name: Modify sshd_config for session timeout
+  ansible.builtin.lineinfile:
+    path: "{{ sshd_conf_file }}"
+    regexp: "{{ item.regexp }}"
+    line: "{{ item.line }}"
+  register: session_timeout
+  notify:
+    - Restart sshd
+  with_items:
+    - { regexp: "^.*ClientAliveInterval*", line: "ClientAliveInterval {{ session_timeout }}" }
+    - { regexp: "^.*ClientAliveCountMax*", line: "ClientAliveCountMax 0" }

+ 15 - 7
control_plane/roles/control_plane_security/vars/main.yml

@@ -13,8 +13,9 @@
 #  limitations under the License.
 #  limitations under the License.
 ---
 ---
 
 
-# Usage: set_fqdn.yml
-etc_hosts_file_dest: /etc/hosts
+# Usage: check_prerequisites.yml
+return_status: 200
+server_file: "{{ role_path }}/files/.ipavars.yml"
 file_mode: '0644'
 file_mode: '0644'
 
 
 # Usage: firewall_settings.yml
 # Usage: firewall_settings.yml
@@ -32,9 +33,8 @@ dt_port1: "7389/tcp"
 ntp_port1: "123/udp"
 ntp_port1: "123/udp"
 
 
 # Usage: enable_dnf_module.yml
 # Usage: enable_dnf_module.yml
-os_centos: 'centos'
-os_rocky: 'rocky'
-os_version: '8.0'
+os_supported_centos: "centos"
+os_supported_rocky: "rocky"
 
 
 # Usage: install_packages.yml
 # Usage: install_packages.yml
 ipa_server_packages:
 ipa_server_packages:
@@ -46,5 +46,13 @@ ipa_server_packages:
 # Usage: install_ipa_server.yml
 # Usage: install_ipa_server.yml
 resolv_conf_path: /etc/resolv.conf
 resolv_conf_path: /etc/resolv.conf
 temp_resolv_conf_path: /tmp/resolv.conf
 temp_resolv_conf_path: /tmp/resolv.conf
-resolv_file_mode: '0644'
-server_file: "{{ playbook_dir }}/roles/control_plane_security/files/.ipavars.yml"
+ipa_admin_username: admin
+
+# Usage: ipa_configuration.yml
+sysadmin_sudo_rule: sysadmin_sudo
+sysadmin_sudo_rule_description: "Allow users to run sudo commands"
+sysadmin_user_group: sysadmin
+sysadmin_group_description: "User group with sudo permission"
+
+# Usage: session_timeout.yml
+sshd_conf_file: /etc/ssh/sshd_config