Repository: lateralblast/lunar Branch: master Commit: cc174e4dc704 Files: 668 Total size: 1.5 MB Directory structure: gitextract_oer0oofz/ ├── README.md ├── aws/ │ ├── account-creation-policy.json │ ├── iam-manager-policy.json │ ├── iam-master-policy.json │ └── server-access-logging.json ├── changelog ├── docker-compose.yml ├── functions/ │ ├── aix/ │ │ ├── check_auditctl.sh │ │ ├── check_chsec.sh │ │ ├── check_chuser.sh │ │ ├── check_itab.sh │ │ ├── check_lslpp.sh │ │ ├── check_no.sh │ │ ├── check_pwpolicy.sh │ │ ├── check_rctcp.sh │ │ ├── check_subserver.sh │ │ └── check_trust.sh │ ├── aws/ │ │ ├── audit_aws.sh │ │ ├── audit_aws_rec_all.sh │ │ ├── check_aws_open_port.sh │ │ └── check_aws_password_policy.sh │ ├── azure/ │ │ ├── compute/ │ │ │ ├── batch/ │ │ │ │ ├── check_azure_batch_pool_value.sh │ │ │ │ └── check_azure_batch_value.sh │ │ │ ├── container/ │ │ │ │ └── check_azure_container_instance_value.sh │ │ │ ├── function/ │ │ │ │ ├── check_azure_function_app_value.sh │ │ │ │ └── check_azure_function_deployment_slot_value.sh │ │ │ ├── vm/ │ │ │ │ └── check_azure_vm_value.sh │ │ │ └── webapp/ │ │ │ ├── check_azure_app_service_app_value.sh │ │ │ ├── check_azure_app_service_ase_value.sh │ │ │ ├── check_azure_app_service_deployment_slot_value.sh │ │ │ └── check_azure_app_service_plan_value.sh │ │ ├── database/ │ │ │ ├── check_azure_cosmos_db_value.sh │ │ │ ├── check_azure_mysql_db_value.sh │ │ │ ├── check_azure_postgresql_db_value.sh │ │ │ ├── check_azure_redis_cache_value.sh │ │ │ ├── check_azure_redis_enterprise_cache_value.sh │ │ │ └── check_azure_sql_db_value.sh │ │ ├── logging/ │ │ │ ├── check_azure_activity_log_alert_value.sh │ │ │ ├── check_azure_monitor_value.sh │ │ │ ├── check_azure_monitoring_diagnostics_value.sh │ │ │ ├── check_azure_network_watcher_flow_log_value.sh │ │ │ ├── check_azure_network_watcher_value.sh │ │ │ └── check_azure_storage_logging_value.sh │ │ ├── network/ │ │ │ ├── check_azure_network_private_endpoint_value.sh │ │ │ ├── check_azure_public_ip_value.sh │ │ │ └── check_azure_vnet_value.sh │ │ ├── other/ │ │ │ └── audit_azure.sh │ │ ├── security/ │ │ │ ├── check_azure_basic_authentication_publishing_credential_value.sh │ │ │ ├── check_azure_lock_value.sh │ │ │ ├── check_azure_microsoft_defender_value.sh │ │ │ ├── check_azure_network_security_perimeter_value.sh │ │ │ ├── check_azure_nsg_security_rule_value.sh │ │ │ ├── check_azure_resource_manager_lock.sh │ │ │ ├── check_azure_security_contact_value.sh │ │ │ ├── check_azure_security_setting.sh │ │ │ └── check_azure_waf_value.sh │ │ ├── storage/ │ │ │ ├── check_azure_backup_policy_value.sh │ │ │ ├── check_azure_data_factory_value.sh │ │ │ ├── check_azure_databox_value.sh │ │ │ ├── check_azure_databricks_value.sh │ │ │ ├── check_azure_elastic_san_value.sh │ │ │ ├── check_azure_file_share_value.sh │ │ │ ├── check_azure_netapp_file_value.sh │ │ │ ├── check_azure_storage_account_container_value.sh │ │ │ ├── check_azure_storage_account_keys_rotation.sh │ │ │ ├── check_azure_storage_account_value.sh │ │ │ ├── check_azure_storage_blob_policy_value.sh │ │ │ ├── check_azure_storage_blob_value.sh │ │ │ ├── check_azure_storage_container_value.sh │ │ │ └── check_azure_storage_fs_value.sh │ │ └── vaults/ │ │ ├── check_azure_backup_vault_value.sh │ │ ├── check_azure_key_vault_key_value.sh │ │ ├── check_azure_key_vault_value.sh │ │ └── check_azure_recovery_services_vault_value.sh │ ├── command/ │ │ ├── check_command_output.sh │ │ └── check_command_value.sh │ ├── darwin/ │ │ ├── check_dscl.sh │ │ ├── check_launchctl_service.sh │ │ ├── check_osx_defaults.sh │ │ ├── check_osx_systemsetup.sh │ │ ├── check_pmset.sh │ │ └── check_sysadminctl.sh │ ├── docker/ │ │ ├── audit_docker.sh │ │ └── check_dockerd.sh │ ├── file/ │ │ ├── audit_search_fs.sh │ │ ├── audit_select.sh │ │ ├── audit_test_subset.sh │ │ ├── backup_file.sh │ │ ├── check_append_file.sh │ │ ├── check_file_comment.sh │ │ ├── check_file_exists.sh │ │ ├── check_file_perms.sh │ │ ├── check_file_value.sh │ │ ├── disable_value.sh │ │ ├── replace_file_value.sh │ │ ├── restore_file.sh │ │ └── update_log_file.sh │ ├── kubernetes/ │ │ └── audit_kubernetes.sh │ ├── linux/ │ │ ├── check_ausearch.sh │ │ ├── check_chkconfig_service.sh │ │ ├── check_debian_package.sh │ │ ├── check_gsettings_value.sh │ │ ├── check_linux_package.sh │ │ ├── check_linux_service.sh │ │ ├── check_systemctl_service.sh │ │ └── check_xinetd_service.sh │ ├── packages/ │ │ └── check_package.sh │ ├── services/ │ │ └── check_inetd_service.sh │ └── sunos/ │ ├── audit_system.sh │ ├── audit_system_sparc.sh │ ├── audit_system_x86.sh │ ├── check_initd_service.sh │ ├── check_service.sh │ ├── check_solaris_package.sh │ ├── check_sunos_service.sh │ ├── check_svcadm_service.sh │ └── create_ndd_script.sh ├── lunar.sh ├── main/ │ ├── check_environment.sh │ ├── check_os_release.sh │ ├── check_shellcheck.sh │ ├── get_info.sh │ └── print_info.sh └── modules/ ├── accounting/ │ ├── audit_filesystem_partitions.sh │ ├── audit_kernel_accounting.sh │ ├── audit_process_accounting.sh │ ├── audit_sar_accounting.sh │ ├── audit_system_accounting.sh │ ├── audit_system_accounts.sh │ ├── audit_system_auth.sh │ ├── audit_system_auth_account_reset.sh │ ├── audit_system_auth_no_magic_root.sh │ ├── audit_system_auth_nullok.sh │ ├── audit_system_auth_unlock_time.sh │ ├── audit_system_auth_use_uid.sh │ └── audit_system_integrity.sh ├── aix/ │ ├── audit_i4ls.sh │ └── audit_writesrv.sh ├── apache/ │ └── audit_apache.sh ├── audit/ │ └── audit_auditd.sh ├── aws/ │ ├── compute/ │ │ ├── audit_aws_ec2.sh │ │ ├── audit_aws_elb.sh │ │ ├── audit_aws_es.sh │ │ ├── audit_aws_rec_ec2.sh │ │ ├── audit_aws_rec_elb.sh │ │ ├── audit_aws_rec_es.sh │ │ └── audit_aws_ses.sh │ ├── config/ │ │ ├── audit_aws_cf.sh │ │ ├── audit_aws_config.sh │ │ └── audit_aws_support_role.sh │ ├── database/ │ │ ├── audit_aws_ec.sh │ │ ├── audit_aws_rds.sh │ │ ├── audit_aws_rec_dynamodb.sh │ │ ├── audit_aws_rec_ec.sh │ │ ├── audit_aws_rec_rds.sh │ │ ├── audit_aws_rec_redshift.sh │ │ └── audit_aws_redshift.sh │ ├── logging/ │ │ ├── audit_aws_inspector.sh │ │ ├── audit_aws_logging.sh │ │ ├── audit_aws_monitoring.sh │ │ ├── audit_aws_rec_inspector.sh │ │ ├── audit_aws_rec_monitoring.sh │ │ └── audit_aws_sns.sh │ ├── network/ │ │ ├── audit_aws_dns.sh │ │ ├── audit_aws_rec_vpcs.sh │ │ └── audit_aws_vpcs.sh │ ├── security/ │ │ ├── audit_aws_access_keys.sh │ │ ├── audit_aws_certs.sh │ │ ├── audit_aws_creds.sh │ │ ├── audit_aws_iam.sh │ │ ├── audit_aws_keys.sh │ │ ├── audit_aws_mfa.sh │ │ ├── audit_aws_password_policy.sh │ │ └── audit_aws_sgs.sh │ └── storage/ │ ├── audit_aws_cdn.sh │ └── audit_aws_s3.sh ├── azure/ │ ├── compute/ │ │ ├── batch/ │ │ │ └── audit_azure_batch.sh │ │ ├── container/ │ │ │ └── audit_azure_container_instances.sh │ │ ├── cycle/ │ │ │ └── audit_azure_cycle_cloud.sh │ │ ├── function/ │ │ │ ├── apps/ │ │ │ │ ├── audit_azure_function_app_basic_authentication_publishing_credentials.sh │ │ │ │ ├── audit_azure_function_app_client_certificates.sh │ │ │ │ ├── audit_azure_function_app_cross_origin_resource_sharing.sh │ │ │ │ ├── audit_azure_function_app_ftp_states.sh │ │ │ │ ├── audit_azure_function_app_http_values.sh │ │ │ │ ├── audit_azure_function_app_java_versions.sh │ │ │ │ ├── audit_azure_function_app_managed_identities.sh │ │ │ │ ├── audit_azure_function_app_public_network_access.sh │ │ │ │ ├── audit_azure_function_app_python_versions.sh │ │ │ │ ├── audit_azure_function_app_remote_debugging.sh │ │ │ │ ├── audit_azure_function_app_service_authentication.sh │ │ │ │ ├── audit_azure_function_app_tls_values.sh │ │ │ │ ├── audit_azure_function_app_virtual_network_integration.sh │ │ │ │ └── audit_azure_function_apps.sh │ │ │ └── slots/ │ │ │ ├── audit_azure_function_deployment_slots.sh │ │ │ ├── audit_azure_function_deployment_slots_basic_authentication_publishing_credentials.sh │ │ │ ├── audit_azure_function_deployment_slots_client_certificates.sh │ │ │ ├── audit_azure_function_deployment_slots_cross_origin_resource_sharing.sh │ │ │ ├── audit_azure_function_deployment_slots_ftp_states.sh │ │ │ ├── audit_azure_function_deployment_slots_http_values.sh │ │ │ ├── audit_azure_function_deployment_slots_java_versions.sh │ │ │ ├── audit_azure_function_deployment_slots_managed_identities.sh │ │ │ ├── audit_azure_function_deployment_slots_private_endpoints.sh │ │ │ ├── audit_azure_function_deployment_slots_public_network_access.sh │ │ │ ├── audit_azure_function_deployment_slots_python_versions.sh │ │ │ ├── audit_azure_function_deployment_slots_remote_debugging.sh │ │ │ ├── audit_azure_function_deployment_slots_tls_values.sh │ │ │ └── audit_azure_function_deployment_slots_virtual_network_integration.sh │ │ ├── main/ │ │ │ └── audit_azure_compute_services.sh │ │ ├── vm/ │ │ │ └── audit_azure_vms.sh │ │ └── webapp/ │ │ ├── apps/ │ │ │ ├── audit_azure_app_service_apps.sh │ │ │ ├── audit_azure_app_service_ases.sh │ │ │ ├── audit_azure_app_service_authentication.sh │ │ │ ├── audit_azure_app_service_basic_authentication_publishing_credential_values.sh │ │ │ ├── audit_azure_app_service_client_certificates.sh │ │ │ ├── audit_azure_app_service_cross_origin_resource_sharing.sh │ │ │ ├── audit_azure_app_service_ftp_states.sh │ │ │ ├── audit_azure_app_service_http_logs.sh │ │ │ ├── audit_azure_app_service_http_values.sh │ │ │ ├── audit_azure_app_service_java_versions.sh │ │ │ ├── audit_azure_app_service_managed_identies.sh │ │ │ ├── audit_azure_app_service_php_versions.sh │ │ │ ├── audit_azure_app_service_plans.sh │ │ │ ├── audit_azure_app_service_private_dns_zones.sh │ │ │ ├── audit_azure_app_service_private_endpoints.sh │ │ │ ├── audit_azure_app_service_public_network_access.sh │ │ │ ├── audit_azure_app_service_python_versions.sh │ │ │ ├── audit_azure_app_service_remote_debugging.sh │ │ │ ├── audit_azure_app_service_tls_values.sh │ │ │ ├── audit_azure_app_service_virtual_network_integration.sh │ │ │ └── audit_azure_app_service_vnets.sh │ │ └── slots/ │ │ ├── audit_azure_app_service_deployment_slots.sh │ │ ├── audit_azure_app_service_deployment_slots_basic_authentication_publishing_credentials.sh │ │ ├── audit_azure_app_service_deployment_slots_client_certificates.sh │ │ ├── audit_azure_app_service_deployment_slots_cross_origin_resource_sharing.sh │ │ ├── audit_azure_app_service_deployment_slots_ftp_states.sh │ │ ├── audit_azure_app_service_deployment_slots_http_values.sh │ │ ├── audit_azure_app_service_deployment_slots_java_versions.sh │ │ ├── audit_azure_app_service_deployment_slots_managed_identities.sh │ │ ├── audit_azure_app_service_deployment_slots_php_versions.sh │ │ ├── audit_azure_app_service_deployment_slots_private_endpoints.sh │ │ ├── audit_azure_app_service_deployment_slots_public_network_access.sh │ │ ├── audit_azure_app_service_deployment_slots_python_versions.sh │ │ ├── audit_azure_app_service_deployment_slots_remote_debugging.sh │ │ ├── audit_azure_app_service_deployment_slots_tls_values.sh │ │ └── audit_azure_app_service_deployment_slots_virtual_network_integration.sh │ ├── database/ │ │ ├── audit_azure_cosmos_db.sh │ │ ├── audit_azure_mysql_db.sh │ │ ├── audit_azure_postgresql_db.sh │ │ ├── audit_azure_redis_cache.sh │ │ └── audit_azure_sql_db.sh │ ├── logging/ │ │ ├── audit_azure_activity_log_alerts.sh │ │ ├── audit_azure_activity_logs_cmk.sh │ │ ├── audit_azure_application_insights.sh │ │ ├── audit_azure_diagnostic_setting_categories.sh │ │ ├── audit_azure_entra_diagnostic_settings.sh │ │ ├── audit_azure_graph_diagnostic_settings.sh │ │ ├── audit_azure_intune_logs.sh │ │ ├── audit_azure_logging_and_monitoring.sh │ │ ├── audit_azure_resource_logging.sh │ │ └── audit_azure_subscription_diagnostic_settings.sh │ ├── main/ │ │ ├── audit_azure_custom_subscription_admin_roles.sh │ │ ├── audit_azure_extensions.sh │ │ ├── audit_azure_sku_basic_consumption.sh │ │ ├── audit_azure_subscription_owners.sh │ │ └── audit_azure_survey.sh │ ├── network/ │ │ ├── audit_azure_network_private_endpoints.sh │ │ ├── audit_azure_network_security_perimeter.sh │ │ ├── audit_azure_network_watcher.sh │ │ ├── audit_azure_network_watcher_flow_logs.sh │ │ ├── audit_azure_networking_services.sh │ │ ├── audit_azure_public_ips.sh │ │ ├── audit_azure_virtual_network_flow_logs.sh │ │ └── audit_azure_vnets.sh │ ├── security/ │ │ ├── audit_azure_authentication_type.sh │ │ ├── audit_azure_guest_users.sh │ │ ├── audit_azure_identity_services.sh │ │ ├── audit_azure_locks.sh │ │ ├── audit_azure_microsoft_defender.sh │ │ ├── audit_azure_nsg_flow_logs.sh │ │ ├── audit_azure_nsg_security_rules.sh │ │ ├── audit_azure_security_contacts.sh │ │ ├── audit_azure_security_services.sh │ │ ├── audit_azure_user_access_admin_role.sh │ │ ├── audit_azure_waf.sh │ │ ├── audit_azure_waf_inspection_policy.sh │ │ └── audit_azure_waf_ssl_policy.sh │ ├── storage/ │ │ ├── audit_azure_blob_storage.sh │ │ ├── audit_azure_data_factory.sh │ │ ├── audit_azure_database_services.sh │ │ ├── audit_azure_databox.sh │ │ ├── audit_azure_databricks.sh │ │ ├── audit_azure_elastic_san.sh │ │ ├── audit_azure_file_shares.sh │ │ ├── audit_azure_managed_lustre.sh │ │ ├── audit_azure_netapp_files.sh │ │ ├── audit_azure_storage_account_locks.sh │ │ ├── audit_azure_storage_accounts.sh │ │ ├── audit_azure_storage_logging.sh │ │ └── audit_azure_storage_services.sh │ └── vaults/ │ ├── audit_azure_backup_vaults.sh │ ├── audit_azure_key_vault_certificates.sh │ ├── audit_azure_key_vault_keys.sh │ ├── audit_azure_key_vault_logging.sh │ ├── audit_azure_key_vault_private_endpoints.sh │ ├── audit_azure_key_vault_public_network_access.sh │ ├── audit_azure_key_vault_purge_protection.sh │ ├── audit_azure_key_vault_rbac.sh │ ├── audit_azure_key_vault_secrets.sh │ └── audit_azure_recovery_services_vaults.sh ├── bluetooth/ │ └── audit_bluetooth.sh ├── boot/ │ ├── audit_boot_server.sh │ ├── audit_bootparams.sh │ └── audit_grub_security.sh ├── core/ │ ├── audit_core_dumps.sh │ ├── audit_core_limit.sh │ └── audit_core_storage.sh ├── cron/ │ ├── audit_cron.sh │ ├── audit_cron_allow.sh │ ├── audit_cron_logging.sh │ └── audit_cron_perms.sh ├── darwin/ │ ├── audit_account_lockout.sh │ ├── audit_account_switching.sh │ ├── audit_ad_tracking.sh │ ├── audit_air_drop.sh │ ├── audit_air_play.sh │ ├── audit_amfi.sh │ ├── audit_apfs.sh │ ├── audit_app_perms.sh │ ├── audit_asl.sh │ ├── audit_asset_cache.sh │ ├── audit_auto_login.sh │ ├── audit_auto_logout.sh │ ├── audit_bonjour_advertising.sh │ ├── audit_cd_sharing.sh │ ├── audit_file_sharing.sh │ ├── audit_file_vault.sh │ ├── audit_gate_keeper.sh │ ├── audit_guest_sharing.sh │ ├── audit_icloud_drive.sh │ ├── audit_infrared_remote.sh │ ├── audit_internet_sharing.sh │ ├── audit_java.sh │ ├── audit_keychain_lock.sh │ ├── audit_keychain_sync.sh │ ├── audit_location_services.sh │ ├── audit_lockdown.sh │ ├── audit_media_sharing.sh │ ├── audit_remote_apple_events.sh │ ├── audit_safari_allow_popups.sh │ ├── audit_safari_auto_fill.sh │ ├── audit_safari_auto_run.sh │ ├── audit_safari_history.sh │ ├── audit_safari_javascript.sh │ ├── audit_safari_show_statusbar.sh │ ├── audit_safari_tracking.sh │ ├── audit_safari_warn.sh │ ├── audit_safe_downloads.sh │ ├── audit_screen_corner.sh │ ├── audit_screen_lock.sh │ ├── audit_screen_sharing.sh │ ├── audit_siri.sh │ ├── audit_sleep.sh │ ├── audit_software_update.sh │ ├── audit_sys_suspend.sh │ ├── audit_system_preferences.sh │ ├── audit_time_machine.sh │ ├── audit_touch_id.sh │ ├── audit_universal_control.sh │ ├── audit_usage_data.sh │ ├── audit_wake_on_lan.sh │ ├── audit_web_sharing.sh │ └── audit_wireless.sh ├── dhcp/ │ ├── audit_dhcp_server.sh │ ├── audit_dhcpcd.sh │ ├── audit_dhcprd.sh │ └── audit_dhcpsd.sh ├── dns/ │ ├── audit_dns_client.sh │ └── audit_dns_server.sh ├── docker/ │ ├── audit_docker_daemon.sh │ ├── audit_docker_logging.sh │ ├── audit_docker_monitoring.sh │ ├── audit_docker_network.sh │ ├── audit_docker_security.sh │ └── audit_docker_users.sh ├── esxi/ │ ├── audit_dcui.sh │ ├── audit_dvfilter.sh │ ├── audit_esxi_shell.sh │ └── audit_mob.sh ├── firewall/ │ ├── audit_firewall_setting.sh │ ├── audit_ipfilter.sh │ ├── audit_ipfw.sh │ ├── audit_ipsec.sh │ ├── audit_iptables.sh │ ├── audit_routing_daemons.sh │ ├── audit_routing_params.sh │ ├── audit_suse_firewall.sh │ └── audit_ufw.sh ├── fs/ │ ├── audit_autofs.sh │ ├── audit_file_extensions.sh │ ├── audit_file_metadata.sh │ ├── audit_file_perms.sh │ ├── audit_hotplug.sh │ ├── audit_nfs.sh │ ├── audit_samba.sh │ ├── audit_setup_file.sh │ ├── audit_smbconf_perms.sh │ ├── audit_sticky_bit.sh │ ├── audit_suid_files.sh │ ├── audit_unowned_files.sh │ ├── audit_user_dotfiles.sh │ ├── audit_user_netrc.sh │ ├── audit_user_rhosts.sh │ ├── audit_winbind.sh │ └── audit_writable_files.sh ├── ftp/ │ ├── audit_ftp_banner.sh │ ├── audit_ftp_client.sh │ ├── audit_ftp_conf.sh │ ├── audit_ftp_logging.sh │ ├── audit_ftp_server.sh │ ├── audit_ftp_umask.sh │ ├── audit_ftp_users.sh │ ├── audit_tftp_client.sh │ └── audit_tftp_server.sh ├── full/ │ ├── full_audit_accounting_services.sh │ ├── full_audit_disk_services.sh │ ├── full_audit_file_services.sh │ ├── full_audit_firewall_services.sh │ ├── full_audit_ftp_services.sh │ ├── full_audit_hardware_services.sh │ ├── full_audit_kernel_services.sh │ ├── full_audit_log_services.sh │ ├── full_audit_mail_services.sh │ ├── full_audit_naming_services.sh │ ├── full_audit_network_services.sh │ ├── full_audit_osx_services.sh │ ├── full_audit_other_daemons.sh │ ├── full_audit_other_services.sh │ ├── full_audit_password_services.sh │ ├── full_audit_power_services.sh │ ├── full_audit_print_services.sh │ ├── full_audit_routing_services.sh │ ├── full_audit_shell_services.sh │ ├── full_audit_update_services.sh │ ├── full_audit_user_services.sh │ ├── full_audit_virtualisation_services.sh │ ├── full_audit_web_services.sh │ ├── full_audit_windows_services.sh │ └── full_audit_x11_services.sh ├── groups/ │ ├── audit_duplicate_groups.sh │ ├── audit_group_fields.sh │ ├── audit_groups_exist.sh │ └── audit_root_primary_group.sh ├── gui/ │ ├── audit_font_server.sh │ ├── audit_gdm_conf.sh │ ├── audit_gnome_automount.sh │ ├── audit_gnome_banner.sh │ ├── audit_gnome_screen_lock.sh │ ├── audit_kdm_config.sh │ ├── audit_opengl.sh │ └── audit_xwindows_server.sh ├── kerberos/ │ ├── audit_kerberos_tgt.sh │ └── audit_krb5.sh ├── kernel/ │ ├── audit_kernel_modules.sh │ └── audit_kernel_params.sh ├── kubernetes/ │ ├── audit_kubernetes_apiserver.sh │ ├── audit_kubernetes_controller.sh │ ├── audit_kubernetes_etcd.sh │ ├── audit_kubernetes_kubelet.sh │ ├── audit_kubernetes_perms.sh │ └── audit_kubernetes_scheduler.sh ├── ldap/ │ ├── audit_ldap.sh │ ├── audit_ldap_cache.sh │ └── audit_ldap_server.sh ├── linux/ │ ├── audit_aide.sh │ ├── audit_apparmor.sh │ ├── audit_apport.sh │ ├── audit_avahi_conf.sh │ ├── audit_avahi_server.sh │ ├── audit_biosdevname.sh │ ├── audit_execshield.sh │ ├── audit_linux_logfiles.sh │ ├── audit_modprobe_conf.sh │ ├── audit_pae.sh │ ├── audit_prelink.sh │ ├── audit_ptrace_scope.sh │ ├── audit_selinux.sh │ ├── audit_sysctl.sh │ ├── audit_virtual_memory.sh │ ├── audit_xen.sh │ ├── audit_xinetd.sh │ ├── audit_xinetd_server.sh │ └── audit_yum_conf.sh ├── login/ │ ├── audit_console_login.sh │ ├── audit_failed_logins.sh │ ├── audit_issue_banner.sh │ ├── audit_login_delay.sh │ ├── audit_login_details.sh │ ├── audit_login_guest.sh │ ├── audit_login_records.sh │ ├── audit_login_root.sh │ ├── audit_login_warning.sh │ ├── audit_remote_login.sh │ ├── audit_retry_limit.sh │ ├── audit_security_banner.sh │ ├── audit_serial_login.sh │ ├── audit_sulogin.sh │ └── audit_xlogin.sh ├── logs/ │ ├── audit_debug_logging.sh │ ├── audit_inetd_logging.sh │ ├── audit_logadm_value.sh │ └── audit_logrotate.sh ├── mail/ │ ├── audit_email_daemons.sh │ ├── audit_exim.sh │ ├── audit_postfix_daemon.sh │ ├── audit_sendmail_aliases.sh │ ├── audit_sendmail_daemon.sh │ └── audit_sendmail_greeting.sh ├── mounts/ │ ├── audit_mount_fdi.sh │ ├── audit_mount_nodev.sh │ ├── audit_mount_noexec.sh │ └── audit_mount_setuid.sh ├── nis/ │ ├── audit_crypt_policy.sh │ ├── audit_disk_encryption.sh │ ├── audit_encryption_kit.sh │ ├── audit_nis_client.sh │ ├── audit_nis_entries.sh │ ├── audit_nis_server.sh │ └── audit_nisplus.sh ├── ntp/ │ └── audit_ntp.sh ├── pam/ │ ├── audit_pam_authtok.sh │ ├── audit_pam_deny.sh │ ├── audit_pam_gdm_autologin.sh │ ├── audit_pam_rhosts.sh │ └── audit_rsa_securid_pam.sh ├── password/ │ ├── audit_pass_req.sh │ ├── audit_passwd_perms.sh │ ├── audit_password_expiry.sh │ ├── audit_password_fields.sh │ ├── audit_password_hashing.sh │ ├── audit_password_hints.sh │ ├── audit_password_history.sh │ ├── audit_password_lock.sh │ ├── audit_password_strength.sh │ ├── audit_shadow_group.sh │ ├── audit_smbpasswd_perms.sh │ ├── audit_system_auth_password_hashing.sh │ ├── audit_system_auth_password_history.sh │ ├── audit_system_auth_password_policy.sh │ └── audit_system_auth_password_strength.sh ├── power/ │ └── audit_power_management.sh ├── print/ │ ├── audit_cups.sh │ ├── audit_ppd_cache.sh │ ├── audit_print.sh │ └── audit_printer_sharing.sh ├── remote/ │ ├── audit_remote_consoles.sh │ ├── audit_remote_info.sh │ ├── audit_remote_management.sh │ ├── audit_remote_shell.sh │ └── audit_vnc.sh ├── rpc/ │ ├── audit_nobody_rpc.sh │ └── audit_rpc_bind.sh ├── rsh/ │ ├── audit_rsh_client.sh │ └── audit_rsh_server.sh ├── security/ │ ├── audit_secure_empty_trash.sh │ ├── audit_secure_keyboard_entry.sh │ └── audit_secure_swap.sh ├── services/ │ ├── audit_inetd.sh │ ├── audit_ipmi.sh │ ├── audit_ipv6.sh │ ├── audit_iscsi.sh │ ├── audit_legacy.sh │ ├── audit_other_daemons.sh │ ├── audit_postgresql.sh │ ├── audit_rarp.sh │ ├── audit_snmp.sh │ └── audit_unconfined_daemons.sh ├── ssh/ │ ├── audit_root_ssh_keys.sh │ ├── audit_ssh_config.sh │ ├── audit_ssh_forwarding.sh │ └── audit_ssh_perms.sh ├── sudo/ │ ├── audit_sudo_authenticate.sh │ ├── audit_sudo_logfile.sh │ ├── audit_sudo_nopassword.sh │ ├── audit_sudo_perms.sh │ ├── audit_sudo_timeout.sh │ ├── audit_sudo_timestamp.sh │ ├── audit_sudo_usepty.sh │ └── audit_wheel_sudo.sh ├── sunos/ │ ├── audit_apocd.sh │ ├── audit_audit_class.sh │ ├── audit_bpcd.sh │ ├── audit_bpjava_msvc.sh │ ├── audit_cde_banner.sh │ ├── audit_cde_cal.sh │ ├── audit_cde_print.sh │ ├── audit_cde_screen_lock.sh │ ├── audit_cde_spc.sh │ ├── audit_cde_ttdb.sh │ ├── audit_create_class.sh │ ├── audit_dfstab.sh │ ├── audit_echo.sh │ ├── audit_eeprom_security.sh │ ├── audit_extended_attributes.sh │ ├── audit_gss.sh │ ├── audit_ipadm_value.sh │ ├── audit_keyserv.sh │ ├── audit_labeld.sh │ ├── audit_ncs.sh │ ├── audit_ndd_value.sh │ ├── audit_network_connections.sh │ ├── audit_ocfserv.sh │ ├── audit_online_documentation.sh │ ├── audit_privilege_events.sh │ ├── audit_service_tags.sh │ ├── audit_slp.sh │ ├── audit_solaris_auditing.sh │ ├── audit_stack_protection.sh │ ├── audit_svccfg_value.sh │ ├── audit_svm.sh │ ├── audit_svm_gui.sh │ ├── audit_ticotsord.sh │ ├── audit_tname.sh │ ├── audit_tnd.sh │ ├── audit_uucp.sh │ ├── audit_vnetd.sh │ ├── audit_volfs.sh │ ├── audit_vopied.sh │ ├── audit_wbem.sh │ ├── audit_webconsole.sh │ ├── audit_webmin.sh │ ├── audit_wins.sh │ └── audit_zones.sh ├── syslog/ │ ├── audit_syslog_auth.sh │ ├── audit_syslog_conf.sh │ ├── audit_syslog_perms.sh │ └── audit_syslog_server.sh ├── talk/ │ ├── audit_talk_client.sh │ └── audit_talk_server.sh ├── tcp/ │ ├── audit_tcp_strong_iss.sh │ ├── audit_tcp_syn_cookie.sh │ └── audit_tcp_wrappers.sh ├── telnet/ │ ├── audit_telnet_banner.sh │ ├── audit_telnet_client.sh │ └── audit_telnet_server.sh ├── users/ │ ├── audit_daemon_umask.sh │ ├── audit_default_umask.sh │ ├── audit_dot_files.sh │ ├── audit_duplicate_ids.sh │ ├── audit_duplicate_users.sh │ ├── audit_forward_files.sh │ ├── audit_home_ownership.sh │ ├── audit_home_perms.sh │ ├── audit_inactive_users.sh │ ├── audit_mesgn.sh │ ├── audit_netrc_files.sh │ ├── audit_old_users.sh │ ├── audit_reserved_ids.sh │ ├── audit_rhosts_files.sh │ ├── audit_root_access.sh │ ├── audit_root_home.sh │ ├── audit_root_path.sh │ ├── audit_shell_timeout.sh │ ├── audit_shells.sh │ └── audit_super_users.sh └── wheel/ ├── audit_pam_wheel.sh ├── audit_wheel_group.sh ├── audit_wheel_su.sh └── audit_wheel_users.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ ![alt tag](https://raw.githubusercontent.com/lateralblast/lunar/master/lunar.png) LUNAR ===== Lockdown UNix Auditing and Reporting Version ------- Current version 15.9.1 Refer to lunar.sh and changelog for more up to date version information License ------- CC BY-SA: https://creativecommons.org/licenses/by-sa/4.0/ Fund me here: https://ko-fi.com/richardatlateralblast ** NOTICE ** ------------ Run this code in audit more only, e.g. with -a or --audit switch. Run lockdown at your own risk. As per any system change, have backups. I'm working on improving the recovery mode, but there may still be bugs. I've tried to clean up this script as much as possible using shellcheck, and I've enabled the option to use the -e (errexit) and -u (nounset) shell flags to help protect against errors. The -x (xtrace) shell flag can be enabled by using the script with the -Q or --debug flag. Status ------ In progress: - More flexibility in reporting format(s) e.g. CSV - More inline documentation and documentation output - Adding Azure support (current focus) - Adding Kubernetes support - Adding Apache support Introduction ------------ This scripts generates a scored audit report of a Unix host's security. It is based on the CIS and other frameworks. Where possible there are references to the CIS and other benchmarks in the code documentation. Why a shell script? I wanted a tool that was able to run on locked down systems where other tools may not be available. I also wanted a tool that ran on all versions of UNIX. Having said that there are some differences between sh and bash, so I've used functions only from sh. There is no warranty implied or given with this script. My recommendation is to use this script in audit mode only, and address each warning individually via policy, documentation and configuration management. I am by no means a coder, so there are bound to be bugs and better ways to approach things in this script, so a sincere thank you to the people who have provided feedback, updates and patches to fix bugs/features in code. It can also can perform a lockdown. Unlike some other scripts I have added capability to backout changes. Files are backed up using cpio to a directory based on the date. Although it can perform a lockdown, as previously stated, I'd recommend you address the warnings via policy, documentation and configuration management. This is how I use the tool. The AWS Services audit only supports reporting, it does not provide lockdown capability. Supported Operating Systems --------------------------- The following Operating Systems are supported: - Linux - Rocky Linux - RHEL - Centos - Scientific Linux - SLES - Debian - Ubuntu - Amazon Linux - Solaris - Mac OS X - FreeBSD (needs more testing) - AIX (needs more testing) - ESXi (initial support - some tests) Windows support would require the installation of additional software, so I haven't looked into it. Having said that, Windows support may come in the future via bash. Supported Services ------------------ The following services are supported: - AWS - Azure - Entra ID (not complete) - Storage (not complete) - Compute (not complete) - Docker - Kubernetes (not complete) - Apache (not complete) The AWS Services audit uses the AWS CLI, and as such requires a user with the appropriate rights. It does not currently support the lockdown capability, it only supports generating an audit report against the CIS benchmark. There are a couple of the checks that can only be done or resolved via the GUI. An example of this is enabling billing. Refer to the CIS Benchmark for more information. Where possible I've put suggested fix commands in the verbose audit output. Again in some cases, these can only be done by the CLI. Refer to the CIS Benchmark for more information. In addition I've added a recommendations mode that checks AWS against publicly available best practice from companies like Cloud Conformity. Configuration Management ------------------------ The following configuration management output is supported: - Ansible This option outputs example ansible configuration management code/stanzas for implementing the recommendation. Requirements ------------ For UNIX: - Ubuntu / Debian - sysv-rc-conf - bc - finger For AWS: - AWS - AWS CLI - AWS Credentials (API Access and Secret Keys) - Read rights to appropriate AWS services, e.g. - CloudTrail:DescribeTrails - Config:DescribeConfigurationRecorders - SNS:ListSubscriptionsByTopic For Azure: - Azure - Azure CLI - Extensions - databricks - bastion - resource-graph - application-insights Usage ----- ``` Usage: ./lunar.sh -switch|--switch switch(es): ----------- -1|--list) List changes/backups -2|--tests) Print tests -3|--printfunct) Print function -4|--dryrun) Run in dryrun mode -6|--format) Outpt format/type -7|--file) Output file -8|--usesudo) Use sudo -9|--shellcheck) Run shellcheck against script -0|--force) Force action -a|--audit) Run in audit mode (for Operating Systems - no changes made to system) -A|--fullaudit) Run in audit mode and include filesystems (for Operating Systems - no changes made to system) -b|--backups|--listbackups) List backups -B|--basedir) Set base directory -c|--codename|--distro) Distro/Code name (used with docker/multipass) -C|--shell) Run docker-compose testing suite (drops to shell in order to do more testing) -d|--dockeraudit) Run in audit mode (for Docker - no changes made to system) -D|--dockertests) List all Docker functions available to selective mode -e|--host) Run in audit mode on external host (for Operating Systems - no changes made to system) -E|--hash|--passwordhash) Password hash -f|--action) Action (e.g delete - used with multipass) -F|--tempfile) Temporary file to use for operations -g|--giturl) Git URL for code to copy to container -G|--wheelgroup) Set wheel group -h|--help) Display help -H|--usage) Display usage -i|--anacron) Enable/Disable anacron -I|--type) Audit type -k|--kubeaudit) Run in audit mode (for Kubernetes - no changes made to system) -K|--function|--test) Do a specific function -l|--lockdown) Run in lockdown mode (for Operating Systems - changes made to system) -L|--fulllockdown|fulllock) Run in lockdown mode (for Operating Systems - changes made to system) -m|--machine|--vm) Set virtualisation type -M|--workdir) Set work directory -n|--ansible) Output ansible -N|--nocat) Do output cat in score -o|--os|--osver) Set OS version -O|--osinfo|--systeminfo) Print OS/System information -p|--previous) Print previous audit information -P|--sshsandbox|--sandbox) Enable/Disabe SSH sandbox -q|--quiet|--nostrict) Run in quiet mode -Q|--debug) Run in debug mode -r|--awsregion|--region) Set AWS region -R|--moduleinfo|--testinfo) Print information about a module -s|--select|--check) Run in selective mode (only run tests you want to) -S|--unixtests|--unix) List UNIX tests -t|--tag|--name) Set docker tag -T|--tempdir) Set temp directoru -u|--undo) Undo lockdown (for Operating Systems - changes made to system) -U|--dofiles) Include filesystems -v|--verbose) Run in verbose mode -V|--version) Print version -w|--awsaudit) Run in audit mode (for AWS - no changes made to system) -W|--awstests|--aws) List all AWS functions available to selective mode -x|--awsrec) Run in recommendations mode (for AWS - no changes made to system) -X|--strict) Run shellcheck against script -z) Run specified audit function in lockdown mode -Z|--changes|--listchanges) List changes ``` Examples -------- Perform full audit (without recursive file system checks): ``` ./lunar.sh --audit ``` List tests: ``` ./lunar.sh --tests ``` List AWS tests: ``` ./lunar.sh --tests aws ``` Do a specific test: ``` ./lunar.sh --audit --select remote_shell ``` Create a Ubuntu 24.04 multipass VM for testing: ``` ./lunar.sh --action create --machine multipass --osver 24.04 ``` More Information ---------------- For more information refer to wiki: [Wiki](https://github.com/lateralblast/lunar/wiki) [Usage](https://github.com/lateralblast/lunar/wiki/Usage) [Ansible](https://github.com/lateralblast/lunar/wiki/Ansible) [Ubuntu](https://github.com/lateralblast/lunar/wiki/Ubuntu) [Solaris 11](https://github.com/lateralblast/lunar/wiki/Solaris_11) [CentOS](https://github.com/lateralblast/lunar/wiki/CentOS) [Amazon Linux](https://github.com/lateralblast/lunar/wiki/Amazon) [AWS](https://github.com/lateralblast/lunar/wiki/AWS) [Docker](https://github.com/lateralblast/lunar/wiki/Docker) Testing ------- Added a simple testing framework for debugging the lunar script itself. This uses docker compose to start a container, mount the lunar directory and run lunar. ================================================ FILE: aws/account-creation-policy.json ================================================ { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } ================================================ FILE: aws/iam-manager-policy.json ================================================ { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:AddUserToGroup", "iam:AttachGroupPolicy", "iam:DeleteGroupPolicy", "iam:DeleteUserPolicy", "iam:DetachGroupPolicy", "iam:DetachRolePolicy", "iam:DetachUserPolicy", "iam:PutGroupPolicy", "iam:PutUserPolicy", "iam:RemoveUserFromGroup", "iam:UpdateGroup", "iam:UpdateAssumeRolePolicy", "iam:UpdateUser", "iam:GetPolicy", "iam:GetPolicyVersion", "iam:GetRole", "iam:GetRolePolicy", "iam:GetUser", "iam:GetUserPolicy", "iam:ListEntitiesForPolicy", "iam:ListGroupPolicies", "iam:ListGroups", "iam:ListGroupsForUser", "iam:ListPolicies", "iam:ListPoliciesGrantingServiceAccess", "iam:ListPolicyVersions", "iam:ListRolePolicies", "iam:ListAttachedGroupPolicies", "iam:ListAttachedRolePolicies", "iam:ListAttachedUserPolicies", "iam:ListRoles", "iam:ListUsers" ], "Resource": "*" }, { "Effect": "Deny", "Action": [ "iam:CreateGroup", "iam:CreatePolicy", "iam:CreatePolicyVersion", "iam:CreateRole", "iam:CreateUser", "iam:DeleteGroup", "iam:DeletePolicy", "iam:DeletePolicyVersion", "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DeleteUser", "iam:PutRolePolicy" ], "Resource": "*" } ] } ================================================ FILE: aws/iam-master-policy.json ================================================ { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:CreateGroup", "iam:CreatePolicy", "iam:CreatePolicyVersion", "iam:CreateRole", "iam:CreateUser", "iam:DeleteGroup", "iam:DeletePolicy", "iam:DeletePolicyVersion", "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DeleteUser", "iam:PutRolePolicy", "iam:GetPolicy", "iam:GetPolicyVersion", "iam:GetRole", "iam:GetRolePolicy", "iam:GetUser", "iam:GetUserPolicy", "iam:ListEntitiesForPolicy", "iam:ListGroupPolicies", "iam:ListGroups", "iam:ListGroupsForUser", "iam:ListPolicies", "iam:ListPoliciesGrantingServiceAccess", "iam:ListPolicyVersions", "iam:ListRolePolicies", "iam:ListAttachedGroupPolicies", "iam:ListAttachedRolePolicies", "iam:ListAttachedUserPolicies", "iam:ListRoles", "iam:ListUsers" ], "Resource": "*" }, { "Effect": "Deny", "Action": [ "iam:AddUserToGroup", "iam:AttachGroupPolicy", "iam:DeleteGroupPolicy", "iam:DeleteUserPolicy", "iam:DetachGroupPolicy", "iam:DetachRolePolicy", "iam:DetachUserPolicy", "iam:PutGroupPolicy", "iam:PutUserPolicy", "iam:RemoveUserFromGroup", "iam:UpdateGroup", "iam:UpdateAssumeRolePolicy", "iam:UpdateUser" ], "Resource": "*" } ] } ================================================ FILE: aws/server-access-logging.json ================================================ { "LoggingEnabled": { "TargetBucket": "webapp-service-reports", "TargetPrefix": "access-logs/", "TargetGrants": [ { "Grantee": { "Type": "Group", "URI": "http://acs.amazonaws.com/groups/s3/LogDelivery" }, "Permission": "WRITE" }, { "Grantee": { "Type": "Group", "URI": "http://acs.amazonaws.com/groups/s3/LogDelivery" }, "Permission": "READ_ACP" } ] } } ================================================ FILE: changelog ================================================ # Changes: # 0.0.0 Thursday, 25 October 2012 9:40:54 AM EST # Initial version # 0.0.1 Thursday, 1 November 2012 2:28:41 PM EST # Added initial audit code # 0.0.2 Fri 2 Nov 2012 13:24:54 EST # Created subroutines for updating files and parameters # 0.0.3 Thursday, 8 November 2012 9:35:19 PM EST # Added restore code # 0.0.4 Saturday, 10 November 2012 11:37:22 AM EST # Added kernel accounting # 1.0.0 Monday, 12 November 2012 10:45:27 AM EST # Initial Github Commit # 1.0.1 Monday, 12 November 2012 9:52:17 PM EST # Formating fixes # 1.0.2 Monday, 12 November 2012 10:03:54 PM EST # Additional cleanup # 1.0.3 Thu 15 Nov 2012 02:37:31 EST # Initial Solaris 11 support # 1.0.4 Fri 16 Nov 2012 10:57:17 EST # Updated Solaris 11 support, Initial re-commit to new repository # 1.0.5 Sat 17 Nov 2012 09:55:07 EST # Added echo services # 1.0.6 Monday, 19 November 2012 8:13:20 AM EST # Solaris 10 and 11 support mostly done - some minor additions could be made # 1.0.7 Monday, 19 November 2012 11:02:05 AM EST # Added initial support for Solaris versions less than 10 # 1.0.8 Thursday, 20 December 2012 2:46:32 PM EST # Fixed problem with inetadm command # 1.0.9 Thursday, 20 December 2012 3:47:52 PM EST # Added -A and -L switches and moved filesystem searches to it # 1.1.0 Thu 20 Dec 2012 17:01:52 EST # Cleaned up formating # 1.1.1 Fri Dec 21 21:43:39 EST 2012 # Initial Solaris 9 testing completed # 1.1.2 Sat Dec 22 08:13:17 EST 2012 # Fixed bugs with parameter value checking # 1.1.3 Sat Dec 22 08:27:53 EST 2012 # Fixed bug with home directory check # 1.1.4 Sat Dec 22 08:50:38 EST 2012 # Fixed bug with inetd code # 1.1.5 Sat Dec 22 08:54:05 EST 2012 # Fixed Solaris 9 update version detection # 1.1.6 Sat Dec 22 16:45:16 EST 2012 # Updated documentation # 1.1.7 Thu Feb 14 20:46:31 EST 2013 # Initial Linux support # 1.1.8 Fri Feb 15 18:40:48 EST 2013 # Linux xinetd and chkconfig support added # 1.1.9 Sat Feb 16 12:01:05 EST 2013 # Added sysctl audit for Linux # 1.2.0 Sat Feb 16 14:09:03 EST 2013 # Added ftpd logging checking for Linux # 1.2.1 Sat Feb 16 14:22:58 EST 2013 # Updated file update to support tabs # 1.2.2 Sat Feb 16 22:30:05 EST 2013 # Added pam options for Linux # 1.2.3 Sun Feb 17 02:17:04 EST 2013 # Added code for sendmail greeting # 1.2.4 Sun 17 Feb 2013 08:27:32 EST # Added code for vsftpd banner # 1.2.5 Sun Feb 17 19:55:54 EST 2013 # Added securetty check for Linux # 1.2.6 Sun 17 Feb 2013 20:40:27 EST # Added auditd config # 1.2.7 Mon Feb 18 03:11:37 EST 2013 # Added warning banners # 1.2.8 Mon Feb 18 04:42:08 EST 2013 # Added X11 warning messages # 1.2.9 Mon Feb 18 09:41:55 EST 2013 # Added Linux core dumps and rhosts for PAM # 1.3.0 Mon Feb 18 13:42:24 EST 2013 # Added gdm.conf audit # 1.3.1 Mon Feb 18 14:38:04 EST 2013 # Added Linux nodev audit # 1.3.2 Mon Feb 18 15:08:26 EST 2013 # Added Linux FDI audit # 1.3.3 Mon Feb 18 17:53:30 EST 2013 # Added X11 nolisten # 1.3.4 Mon Feb 18 20:30:30 EST 2013 # Improved file octal derivation on Solaris # 1.3.5 Tue Feb 19 12:47:55 EST 2013 # Added file verification for Linux # 1.3.6 Tue Feb 19 14:48:33 EST 2013 # Added password strength testing on Linux # 1.3.7 Tue Feb 19 15:09:05 EST 2013 # Added Cipher directive to SSH config # 1.3.8 Tue Feb 19 15:37:52 EST 2013 # Added logrotate configuration # 1.3.9 Tue Feb 19 15:52:20 EST 2013 # Added module loading and mounting to auditd # 1.4.0 Tue Feb 19 17:03:17 EST 2013 # Added modprobe.conf check # 1.4.1 Tue Feb 19 17:25:39 EST 2013 # Added sendmail local-only mode check # 1.4.2 Tue Feb 19 17:32:12 EST 2013 # Added code to check NTP running as ntp user # 1.4.3 Tue Feb 19 21:01:02 EST 2013 # Added selective function to run individual tests # 1.4.4 Tue Feb 19 21:34:30 EST 2013 # Added selinux # 1.4.5 Tue Feb 19 21:46:55 EST 2013 # Added yum config check # 1.4.6 Tue Feb 19 22:59:12 EST 2013 # Added lockout for failed password attempts # 1.4.7 Wed Feb 20 10:13:46 EST 2013 # Simplified RPM verify routine # 1.4.8 Wed Feb 20 10:59:28 EST 2013 # Added root primary group audit # 1.4.9 Wed Feb 20 11:16:28 EST 2013 # Added system account shell check # 1.5.0 Wed Feb 20 15:00:07 EST 2013 # Added handling for [at,cron].[deny,allow] # 1.5.1 Wed Feb 20 16:03:18 EST 2013 # Fixed file append function # 1.5.2 Thu Feb 21 14:00:42 EST 2013 # Fixed code to update files # 1.5.3 Thursday, 21 February 2013 3:29:49 PM EST # Improved code to fix cron # 1.5.4 Thu Feb 21 16:49:46 EST 2013 # Added rpm check code # 1.5.5 Fri 22 Feb 2013 07:23:16 EST # Cleaned up code for selective audit # 1.5.6 Fri 3 May 2013 16:25:36 EST # Fixed minor bug with for loop # 1.5.7 Fri May 24 15:46:54 EST 2013 # Initial Debian/Ubuntu support # 1.5.8 Fri May 24 21:04:33 EST 2013 # Improved Debian/Ubuntu support # 1.5.9 Sat May 25 11:40:50 EST 2013 # Improved Debian/Ubuntu support # 1.6.0 Sat May 25 22:35:36 EST 2013 # Improved Debian/Ubuntu support # 1.6.1 Sun Jun 9 09:05:44 EST 2013 # Added some file checks # 1.6.2 Sun Jun 9 23:18:37 EST 2013 # Improved documentation # 1.6.3 Tue Jun 11 14:25:01 EST 2013 # Updated documentation and added verbose mode # 1.6.4 Wed Jun 12 10:35:31 EST 2013 # Fixed NTP test and added audit test information # 1.6.5 Wed Jun 12 17:13:57 EST 2013 # Added inital SUSE support # 1.6.6 Thu Jun 13 16:50:19 EST 2013 # Added OS X support # 1.6.7 Thu Jun 13 19:09:55 EST 2013 # Added Cyrus and Qpopper check # 1.6.8 Thu Jun 13 19:23:10 EST 2013 # Added Postfix check # 1.6.9 Thu Jun 13 19:52:00 EST 2013 # support # 1.7.0 Wed 21 Aug 2013 15:50:51 EST # Added check for root SSH keys # 1.7.1 Wed 21 Aug 2013 15:57:47 EST # Added check for SYSLOG=YES in /etc/default/login for Solaris # 1.7.2 Wed 21 Aug 2013 16:10:15 EST # Added DISABLETIME flag to /etc/default/login check for Solaris # 1.7.3 Wed 21 Aug 2013 16:16:45 EST # Added check for LOG_FROM_REMOTE=NO in /etc/default/syslogd for Solaris # 1.7.4 Sun 25 Aug 2013 19:35:39 EST # Fixed ssh key check code # 1.7.5 Thu 29 Aug 2013 15:12:31 EST # Added su wheel group check # 1.7.6 Thu 29 Aug 2013 15:33:13 EST # Added check for users that have never logged in to make sure accounts are locked # 1.7.7 Fri 30 Aug 2013 15:01:51 EST # Added default crypto check # 1.7.8 Fri 30 Aug 2013 15:16:08 EST # Added code to check wheel group users # 1.7.9 Fri 30 Aug 2013 15:45:06 EST # Added restore function to wheel checks # 1.8.0 Sat 31 Aug 2013 15:51:56 EST # Added check for PASSREQ = YES in /etc/default/login # 1.8.1 Tue 3 Sep 2013 13:54:12 EST # Added check for SYSLOG = YES in /etc/default/su # 1.8.2 Tue 3 Sep 2013 13:56:58 EST # Added check for MINDIGIT = 1 in /etc/default/passwd # 1.8.3 Tue 3 Sep 2013 14:55:16 EST # Added check for UsePrivilegeSeparation yes in /etc/ssh/sshd_config # 1.8.4 Tue 3 Sep 2013 14:58:27 EST # Added check for PrintMotd no in /etc/ssh/sshd_config # 1.8.5 Tue 3 Sep 2013 15:01:25 EST # Added check for LoginGraceTime 120 in /etc/ssh/sshd_config # 1.8.6 Tue 3 Sep 2013 16:06:05 EST # Added check to make sure shells in /etc/shells exist # 1.8.7 Thu 12 Sep 2013 15:51:09 EST # Added ability to load modules # 1.8.8 Mon Sep 16 05:23:51 EDT 2013 # Bug fixes # 1.8.9 Mon Sep 16 19:38:17 EST 2013 # Fixed logrotate check # 1.9.0 Mon 16 Sep 2013 20:03:12 EST # Fixed scoring on root group check # 1.9.1 Mon Sep 16 20:07:42 EST 2013 # Added fix information to root SSH key check # 1.9.2 Mon 16 Sep 2013 20:28:54 EST # Fixed home directory permissions check # 1.9.3 Mon 16 Sep 2013 21:02:02 EST # Fix dot file checking # 1.9.4 Mon 16 Sep 2013 21:14:17 EST # Fixed scoring for root PATH check # 1.9.5 Mon 16 Sep 2013 22:23:33 EST # Fixed scoring for empty password field testing # 1.9.6 Tue 17 Sep 2013 08:46:54 EST # Fixed scoring in reserved UID check # 1.9.7 Tue 17 Sep 2013 08:54:15 EST # Fixed scoring for old user logins test # 1.9.8 Tue 17 Sep 2013 10:09:50 EST # Improved checking for old user logins # 1.9.9 Tue 17 Sep 2013 10:42:36 EST # Fixed scoring for System Account audit # 2.0.0 Tue 17 Sep 2013 10:58:53 EST # Numerous bug fixes # 2.0.1 Tue 17 Sep 2013 14:43:54 EST # Improved SNMP daemon check on Linux # 2.0.2 Wed 18 Sep 2013 13:13:23 EST # Added RSA SecurID PAM check # 2.0.3 Fri 20 Sep 2013 16:57:09 EST # Added better handling for *credit password parameters under Linux # 2.0.4 Fri 20 Sep 2013 18:21:21 EST # Cleaned up linux PAM audit # 2.0.5 Sat 21 Sep 2013 15:32:55 EST # Improved linux password history audit # 2.0.6 Wed 9 Oct 2013 09:50:53 EST # Moved directory check # 2.0.7 Wed 9 Oct 2013 09:56:16 EST # Fixed id check under Solaris # 2.0.8 Wed 9 Oct 2013 10:55:38 EST # Fixed call to check_inetd_service # 2.0.9 Wed 9 Oct 2013 10:56:44 EST # Fixed source on Solaris # 2.1.0 Wed 9 Oct 2013 11:19:38 EST # Fixed "==" evaluation # 2.1.1 Wed 9 Oct 2013 14:16:37 EST # Added check for disabled account to system account check # 2.1.2 Wed 9 Oct 2013 14:25:31 EST # Fixed grep command in audit_shells # 2.1.3 Wed 9 Oct 2013 14:28:33 EST # Fixed other grep commands # 2.1.4 Wed 9 Oct 2013 14:36:39 EST # Fixed set command on Solaris # 2.1.5 Wed 9 Oct 2013 14:38:56 EST # Fixed two SunOS checks # 2.1.6 Wed 9 Oct 2013 14:47:08 EST # Fixed message for inactive user account check # 2.1.7 Wed 9 Oct 2013 16:32:47 EST # Fixed scoring on inactive user account check # 2.1.8 Thu 10 Oct 2013 08:46:13 EST # Fixed console report on Solaris # 2.1.9 Thu 10 Oct 2013 09:30:40 EST # Fixed output for check that file ${exists} # 2.2.0 Thu 10 Oct 2013 09:44:36 EST # Fixed scoring for file permissions check # 2.2.1 Thu 10 Oct 2013 09:59:41 EST # Fixed security banner check scoring # 2.2.2 Wed 15 Jan 2014 09:32:48 EST # Fixed bug with shadow check on OS X # 2.2.3 Wed 15 Jan 2014 11:07:20 EST # Minor bug fixes # 2.2.4 Thu 20 Feb 2014 14:55:44 EST # Split code out to be more manageable # 2.2.5 Wed 12 Mar 2014 11:45:34 EST # Various typo fixes # 2.2.6 Thu 13 Mar 2014 15:39:00 EST # Fixed Login Warning for OS X # 2.2.7 Thu 13 Mar 2014 15:59:31 EST # Fixed Launchctl check for OS X # 2.2.8 Thu 13 Mar 2014 16:00:45 EST # Added Apple Remote Events code for OS X # 2.2.9 Fri 14 Mar 2014 09:33:14 EST # Added Internet Sharing code for OS X # 2.3.0 Fri 14 Mar 2014 15:55:55 EST # Added Account Lockout code for OS X # 2.3.1 Mon 17 Mar 2014 06:40:22 EST # Added Printer Sharing code for OS X # 2.3.2 Mon 17 Mar 2014 07:58:31 EST # Added hot corner check to screen lock check for OS X @ 2.3.3 Mon 17 Mar 2014 10:37:20 EST # Added SSH check for OS X # 2.3.4 Mon 17 Mar 2014 11:21:34 EST # Added DVD/CDo sharing check for OS X # 2.3.5 Mon 17 Mar 2014 15:28:31 EST # Added Wake on Lan check for OS X # 2.3.6 Mon 17 Mar 2014 16:00:01 EST # Added File Vault check for OS X # 2.3.7 Mon 17 Mar 2014 17:03:59 EST # Added Gatekeeper check for OS X # 2.3.8 Tue 18 Mar 2014 09:06:10 EST # Added Safe Downloads list check for OS X # 2.3.9 Tue 18 Mar 2014 09:07:23 EST # Updated CIS reference for firewall settings fo OS X # 2.4.0 Tue 18 Mar 2014 09:50:12 EST # Added Secure Keyboard Entry check for OS X # 2.4.1 Tue 18 Mar 2014 11:59:01 EST # Added Secure Empty Trash check for OS X # 2.4.2 Tue 18 Mar 2014 12:09:43 EST # Cleaned up some defaults checks for OS X # 2.4.3 Tue 18 Mar 2014 12:25:29 ES # Added OX Security Auditing check # 2.4.4 Tue 18 Mar 2014 12:38:16 EST # Cleaned up some code # 2.4.5 Tue 18 Mar 2014 15:25:02 EST # Added code to check system log retention on OS X # 2.4.6 Tue 18 Mar 2014 15:44:13 EST # Added code to check bonjour advertising on OS X # 2.4.7 Tue 18 Mar 2014 16:13:11 EST # Added sudo timeout check # 2.4.8 Tue 18 Mar 2014 16:33:21 EST # Added Keychain Lock time check for OS X # 2.4.9 Wed 19 Mar 2014 07:15:21 EST # Added user home directory permisions check for OS X # 2.5.0 Wed 19 Mar 2014 07:32:50 EST # Added autologin check for OS X # 2.5.1 Wed 19 Mar 2014 08:22:03 EST # Added autologout check for OS X # 2.5.2 Wed 19 Mar 2014 08:48:57 EST # Added pwpolicy function for OS X # 2.5.3 Wed 19 Mar 2014 09:13:10 EST # Added password complexity checks for OS X # 2.5.4 Wed 19 Mar 2014 09:18:19 EST # Added CIS reference to account login details check for OS X # 2.5.5 Wed 19 Mar 2014 09:23:03 EST # Added password hints check for OS X # 2.5.6 Wed 19 Mar 2014 09:24:56 EST # Added CIS reference for guest account check for OS X # 2.5.7 Wed 19 Mar 2014 09:27:16 EST # Added CIS reference for guest file sharing check for OS X # 2.5.8 Wed 19 Mar 2014 09:32:40 EST # Added file extensions check for OS X # 2.5.9 Wed 19 Mar 2014 11:36:56 EST # Added Safari Auto-run check for OS X # 2.6.0 Wed 19 Mar 2014 11:42:21 EST # Fixed bug with launchctl check # 2.6.1 Wed 19 Mar 2014 11:44:25 EST # Fixed bug with gatekeeper and wake on lan check # 2.6.2 Wed 19 Mar 2014 12:05:53 EST # Various bug fixes # 2.6.3 Wed 19 Mar 2014 12:20:50 EST # Improved ability to run script as non root user in audit only mode # 2.6.4 Wed 19 Mar 2014 13:24:05 EST # More bug fixes # 2.6.5 Wed 19 Mar 2014 17:10:44 EST # Added swap to nodev check # 2.6.6 Thu 20 Mar 2014 13:52:09 EST # Added nosuid filesystem mount check for Linux # 2.6.7 Thu 20 Mar 2014 14:41:40 EST # Fixed system log check # 2.6.8 Thu 20 Mar 2014 14:45:20 EST # Added aide check for Linux # 2.6.7 Thu 20 Mar 2014 16:55:35 EST # Moved grouped function files to full_* to better distinguish them # 2.6.8 Thu 20 Mar 2014 17:29:21 EST # Added support to old users check to use last rather than finger if finger is not available # 2.6.9 Thu 20 Mar 2014 22:56:31 EST # Updated SELinux check # 2.7.0 Fri 21 Mar 2014 10:29:30 EST # Added CIS reference to unconfined daemons test # 2.7.1 Fri 21 Mar 2014 10:32:24 EST # Added permissions check for /etc/grub to SELinux test # 2.7.2 Fri 21 Mar 2014 10:38:24 EST # Added CIS reference to single user mode test # 2.7.3 Fri 21 Mar 2014 10:46:47 EST # Added core dumps restriction to Linux and added CIS reference # 2.7.4 Fri 21 Mar 2014 10:56:56 EST # Added execshield check # 2.7.6 Fri 21 Mar 2014 14:02:30 EST # Added code to remove telnet-server package on Linux # 2.7.7 Fri 21 Mar 2014 14:06:58 EST # Added code to remove rsh-server on package Linux # 2.7.8 Fri 21 Mar 2014 14:10:30 EST # Added code to remove YP/NIS server packages on Linux # 2.7.9 Fri 21 Mar 2014 14:13:10 EST # Added code to remove tftp-server package on Linux # 2.8.0 Fri 21 Mar 2014 14:29:43 EST # Added /etc/netboot check for Solaris 11 # 2.8.1 Fri 21 Mar 2014 14:51:23 EST # Added code to remove talk-server package on Linux # 2.8.2 Fri 21 Mar 2014 15:14:24 EST # Added code to remove xinetd-server package on Linux # 2.8.3 Fri 21 Mar 2014 15:16:44 EST # Added CIS references for various xinetd based services for Linux # 2.8.4 Fri 21 Mar 2014 15:20:21 EST # Added CIS reference for daemon umask check # 2.8.5 Fri 21 Mar 2014 15:26:05 EST # Added code to remove X Windows package on Linux # 2.8.6 Fri 21 Mar 2014 15:47:54 EST # Fixed bugs with OS vendor determination # 2.8.7 Fri 21 Mar 2014 16:01:40 EST # Moved Avahi server code to separate module and added CIS reference # 2.8.8 Fri 21 Mar 2014 16:10:05 EST # Added code to remove dhcp server package on Linux # 2.8.9 Fri 21 Mar 2014 16:11:40 EST # Added CIS reference for NTP # 2.9.0 Fri 21 Mar 2014 16:19:07 EST # Added code to remove openldap-servers package on Linux # 2.9.1 Fri 21 Mar 2014 16:20:45 EST # Added CIS reference for NFS check # 2.9.2 Sun 23 Mar 2014 12:32:36 EST # Minor bug fixes # 2.9.3 Sun 23 Mar 2014 12:38:22 EST # Added CIS reference to NIS server check and code to remove package on Linux # 2.9.4 Sun 23 Mar 2014 12:46:47 EST # Added package uninstall disable/enable variable # 2.9.5 Sun 23 Mar 2014 12:53:28 EST # Added CIS reference to FTP server check and code to remove package on Linux # 2.9.6 Sun 23 Mar 2014 12:59:18 EST # Added CIS reference to HTTP server check and code to remove package on Linux # 2.9.7 Sun 23 Mar 2014 13:04:24 EST # Added CIS reference for Dovecot check and code to remove package on Linux # 2.9.8 Sun 23 Mar 2014 13:07:47 EST # Added CIS reference to Samba server check and code to remove package on Linux # 2.9.9 Sun 23 Mar 2014 13:11:41 EST # Added CIS reference to Squid server check and code to remove package on Linux # 3.0.0 Sun 23 Mar 2014 13:18:10 EST # Added CIS reference to SNMP check and code to remove package on Linux # 3.0.1 Sun 23 Mar 2014 13:23:20 EST # Added CIS reference to Postfix check and code to check local-only agent mode on Linux # 3.0.2 Sun 23 Mar 2014 13:37:30 EST # Added code to install and configure rsyslog on Linux # 3.0.3 Sun Sun 23 Mar 2014 15:38:27 EST # Added CIS references to system accounting check # 3.0.4 Sun 23 Mar 2014 15:41:50 EST # Added CIS references to logrotate check # 3.0.5 Sun 23 Mar 2014 16:01:36 EST # Added CIS references to sysctl check # 3.0.6 Sun 23 Mar 2014 16:15:53 EST # Added CIS references to TCP wrappers check # 3.0.7 Mon 24 Mar 2014 09:20:12 EST # Added iptables check # 3.0.8 Mon 24 Mar 2014 09:22:53 EST # Added CIS reference to cron permissions check # 3.0.9 Mon 24 Mar 2014 09:35:34 EST # Cleaned up crow.allow test and added CIS reference # 3.1.0 Mon 24 Mar 2014 09:59:21 EST # Added CIS reference to SSH test # 3.1.1 Mon 24 Mar 2014 10:02:57 EST # Added CIS reference to password hashing algorithm test # 3.1.2 Mon 24 Mar 2014 10:10:33 EST # Added CIS reference to password policy test # 3.1.3 Mon 24 Mar 2014 10:26:28 EST # Added CIS reference for account lockout timeout test # 3.1.4 Mon 24 Mar 2014 17:31:53 EST # Added CIS reference for password reuse test # 3.1.5 Mon 24 Mar 2014 17:36:23 EST # Added CIS reference for remote console test # 3.1.6 Mon 24 Mar 2014 17:38:52 EST # Added CIS reference for pam wheel test # 3.1.7 Mon 24 Mar 2014 17:40:29 EST # Added CIS reference for password expiry test # 3.1.8 Mon 24 Mar 2014 17:45:45 EST # Added CIS reference for system account test # 3.1.9 Mon 24 Mar 2014 17:47:28 EST # Added CIS reference for default root group test # 3.2.0 Mon 24 Mar 2014 18:12:53 EST # Added CIS reference for user default umask test # 3.2.1 Mon 24 Mar 2014 19:36:42 EST # Added code to test Gnome login message on Linux # 3.2.2 Mon 24 Mar 2014 21:06:01 EST # Added CIS reference for world writable files test # 3.2.3 Mon 24 Mar 2014 21:09:52 EST # Added CIS reference for unowned file check # 3.2.4 Mon 24 Mar 2014 21:11:25 EST # Added CIS reference for suid system executables test # 3.2.5 Mon 24 Mar 2014 21:14:24 EST # Added CIS reference for password field test # 3.2.6 Mon 24 Mar 2014 21:16:41 EST # Added CIS reference for legacy NIS entries test # 3.2.7 Mon 24 Mar 2014 21:21:11 EST # Added CIS reference for reserved id test # 3.2.8 Mon 24 Mar 2014 21:23:46 EST # Added CIS reference for root path test # 3.2.9 Mon 24 Mar 2014 21:25:58 EST # Added CIS reference for user home permissions test # 3.3.0 Mon 24 Mar 2014 21:27:52 EST # Added CIS reference for user dot files test # 3.3.1 Mon 24 Mar 2014 21:29:32 EST # Added CIS reference for user .netrc test # 3.3.2 Mon 24 Mar 2014 21:35:03 EST # Added CIS reference for user .rhosts test # 3.3.3 Mon 24 Mar 2014 21:39:43 EST # Added CIS reference for group test # 3.3.4 Mon 24 Mar 2014 21:45:24 EST # Added CIS reference for duplicate ids test # 3.3.5 Mon 24 Mar 2014 21:47:39 EST # Added CIS reference for duplicate gids test # 3.3.6 Mon 24 Mar 2014 21:54:09 EST # Added CIS reference for duplicate users test # 3.3.7 Tue 25 Mar 2014 06:21:54 EST # Added CIS reference for user .forward test # 3.3.8 Tue 25 Mar 2014 07:33:44 EST # Fixed screen lock test for OS X # 3.3.9 Tue 25 Mar 2014 07:53:48 EST # Fixed CD sharing test for OS X # 3.4.0 Tue 25 Mar 2014 07:58:34 EST # Fixed printer sharing test for OS X # 3.4.1 Tue 25 Mar 2014 08:09:02 EST # Added firmware password test for OS X # 3.4.2 Tue 25 Mar 2014 08:29:09 EST # Added CIS NTP reference for OS X # 3.4.3 Tue 25 Mar 2014 08:42:51 EST # Added code to add NTP pool servers to config file # 3.4.4 Tue 25 Mar 2014 09:21:15 EST # Improved launchctl function to be able to turn off and on services # 3.4.5 Tue 25 Mar 2014 10:19:31 EST # Added samba config lockdown tests # 3.4.6 Tue 25 Mar 2014 10:27:55 EST # Added apache config lockdown tests # 3.4.7 Tue 25 Mar 2014 10:31:06 EST # Added CIS reference for SSH for OS X # 3.4.8 Tue 25 Mar 2014 10:51:37 EST # Added Xgrid check # 3.4.9 Tue 25 Mar 2014 10:57:18 EST # Added code to disable mDNS on OS X # 3.5.0 Tue 25 Mar 2014 13:47:00 EST # Initial FreeBSD support # 3.5.1 Tue 25 Mar 2014 13:54:21 EST # Added rc.conf and loader.conf support to file functions # 3.5.2 Tue 25 Mar 2014 14:02:58 EST # Added FreeBSD support and CIS reference to SSH test # 3.5.3 Tue 25 Mar 2014 14:14:26 EST # Added CIS reference for FreeBSD for TCP Wrappers and added inetd flag test for FreeBSD # 3.5.4 Tue 25 Mar 2014 14:29:21 EST # Added ipfw code and CIS reference for FreeBSD # 3.5.5 Tue 25 Mar 2014 14:42:04 EST # Added inet/init code and CIS reference for FreeBSD # 3.5.6 Tue 25 Mar 2014 15:32:56 EST # Added daemon umask test and CIS reference for FreeBSD # 3.5.7 Tue 25 Mar 2014 15:40:44 EST # Added syslog and CIS reference for FreeBSD # 3.5.8 Tue 25 test Mar 2014 15:59:26 EST # Added sendmail test and CIS reference for FreeBSD # 3.5.9 Tue 25 Mar 2014 16:04:18 EST # Added bind test and CIS reference for FreeBSD # 3.6.0 Tue 25 Mar 2014 16:27:15 EST # Added NFS test and CIS reference for FreeBSD # 3.6.1 Tue 25 Mar 2014 16:32:36 EST # Added NIS test and CIS reference for FreeBSD # 3.6.2 Tue 25 Mar 2014 16:39:59 EST # Added printing test and CIS reference for FreeBSD # 3.6.3 Tue 25 Mar 2014 16:50:16 EST # Added core dump test and CIS reference for FreeBSD # 3.6.4 Tue 25 Mar 2014 17:02:17 EST # Added kernel parameters code and CIS reference for FreeBSD # 3.6.5 Tue 25 Mar 2014 17:37:52 EST # Added syslog logging entry and CIS reference for FreeBSD while fixing bug with Syslog server code # 3.6.6 Tue 25 Mar 2014 17:48:07 EST # Added system accounting code and CIS reference for FreeBSD # 3.6.7 Tue 25 Mar 2014 17:52:12 EST # Added TCP/UDP packet logging code and CIS reference for FreeBSD # 3.6.8 Tue 25 Mar 2014 21:42:42 EST # Added newsyslog and CIS reference for FreeBSD # 3.6.9 Tue 25 Mar 2014 21:50:08 EST # Added nosuid mount test and CIS reference for FreeBSD # 3.7.0 Tue 25 Mar 2014 21:58:55 EST # Added passwd and group permissions test and CIS reference for FreeBSD # 3.7.1 Tue 25 Mar 2014 22:02:50 EST # Added sticky bit test and CIS reference for FreeBSD # 3.7.2 Tue 25 Mar 2014 22:05:40 EST # Added world writable files test and CIS reference for FreeBSD # 3.7.3 Tue 25 Mar 2014 22:09:34 EST # Added suid and sgid files test and CIS reference for FreeBSD # 3.7.4 Tue 25 Mar 2014 22:15:30 EST # Added user homde directory permissions test and CIS reference for FreeBSD # 3.7.5 Tue 25 Mar 2014 22:18:28 EST # Added unowned files test and CIS reference for FreeBSD # 3.7.6 Tue 25 Mar 2014 22:29:47 EST # Added initial PAM test and CIS reference for FreeBSD # 3.7.7 Tue 25 Mar 2014 22:34:36 EST # Added dotfiles test and CIS reference for FreeBSD # 3.7.8 Tue 25 Mar 2014 22:47:39 EST # Added cron/at test and CIS references for FreeBSD # 3.7.9 Tue 25 Mar 2014 22:54:48 EST # Added security banner test and CIS references for FreeBSD # 3.8.0 Wed 26 Mar 2014 05:57:25 EST # Added X11 listen test and CIS reference for FreeBSD # 3.8.1 Wed 26 Mar 2014 06:09:12 EST # Added system account test and CIS reference for FreeBSD # 3.8.2 Wed 26 Mar 2014 07:13:36 EST # Added toor account test and CIS reference for FreeBSD # 3.8.3 Wed 26 Mar 2014 07:19:10 EST # Added uid 0 test and CIS reference for FreeBSD # 3.8.4 Wed 26 Mar 2014 07:30:35 EST # Added umask test and CIS reference for FreeBSD # 3.8.5 Wed 26 Mar 2014 07:36:10 EST # Added mesg n test and CIS reference for FreeBSD # 3.8.6 Wed 26 Mar 2014 07:45:29 EST # Added password algorithm test and CIS reference for FreeBSD # 3.8.7 Wed 26 Mar 2014 08:35:24 EST # Added serial logins test and CIS reference for FreeBSD # 3.8.8 Wed 26 Mar 2014 08:54:37 EST # Added single user password test and CIS reference for FreeBSD # 3.8.9 Wed 26 Mar 2014 09:20:46 EST # Added X wrapper test and CIS reference for FreeBSD # 3.9.0 Wed 26 Mar 2014 11:21:34 EST # Added initial AIX support # 3.9.1 Wed 26 Mar 2014 13:35:49 EST # Added password parameter tests and CIS references for AIX # 3.9.2 Wed 26 Mar 2014 13:58:21 EST # Added login retry limit test and CIS references for AIX # 3.9.3 Wed 26 Mar 2014 14:06:37 EST # Added rlogin test and CIS reference for AIX # 3.9.4 Wed 26 Mar 2014 14:34:31 EST # Added code to drive chuser and added su group test and CIS reference for AIX # 3.9.5 Wed 26 Mar 2014 16:48:23 EST # Added system user rlogin test and CIS reference for AIX # 3.9.6 Wed 26 Mar 2014 17:37:12 EST # Added code to drive [rm,ls,ch]itab on AIX # 3.9.7 Wed 26 Mar 2014 17:41:27 EST # Added qdaemon test and CIS reference for AIX # 3.9.8 Wed 26 Mar 2014 17:45:23 EST # Added lpd and piobe test and CIS reference for AIX # 3.9.9 Wed 26 Mar 2014 17:50:30 EST # Added dt test and CIS reference for AIX # 4.0.0 Wed 26 Mar 2014 17:54:55 EST # Added rcnfs test and CIS reference for AIX # 4.0.1 Wed 26 Mar 2014 20:36:07 EST # Added world writable files test and CIS reference for AIX # 4.0.2 Wed 26 Mar 2014 20:45:50 EST # Added unowned files test and CIS reference for AIX # 4.0.3 Wed 26 Mar 2014 20:53:15 EST # Added setuid files test and CIS reference for AIX # 4.0.4 Thu 27 Mar 2014 07:41:22 EST # Added Trusted Execution handling code for AIX # 4.0.5 Thu 27 Mar 2014 07:57:51 EST # Added Trusted Execution tests and CIS reference for AIX # 4.0.6 Thu 27 Mar 2014 08:12:32 EST # Added code to check AIX package is installed # 4.0.7 Thu 27 Mar 2014 08:44:18 EST # Added root PATH check and CIS reference for AIX # 4.0.8 Thu 27 Mar 2014 08:48:48 EST # Added duplicate group test and CIS reference for AIX # 4.0.9 Thu 27 Mar 2014 08:52:25 EST # Added duplicate user test and CIS reference for AIX # 4.1.0 Thu 27 Mar 2014 09:01:12 EST # Added empty password field test and CIS reference for AIX # 4.1.1 Thu 27 Mar 2014 09:09:00 EST # Added cron/at allow tests and CIS references for AIX # 4.1.2 Thu 27 Mar 2014 09:14:09 EST # Added security motd test and CIS reference for AIX # 4.1.3 Thu 27 Mar 2014 10:07:11 EST # Added FTP banner test and CIS reference for AIX # 4.1.4 Thu 27 Mar 2014 10:13:14 EST # Added FTP daemon umask test and CIS reference for AIX # 4.1.5 Thu 27 Mar 2014 10:35:00 EST # Added FTP users test and CIS reference for AIX # 4.1.6 Thu 27 Mar 2014 10:55:57 EST # Added sar accounting test and CIS reference for AIX # 4.1.7 Thu 27 Mar 2014 10:58:32 EST # Added mesgn test and CIS reference for AIX # 4.1.8 Thu 27 Mar 2014 11:06:00 EST # Added writesrv test and CIS reference for AIX # 4.1.9 Thu 27 Mar 2014 11:11:56 EST # Added power management test and CIS reference for AIX # 4.2.0 Thu 27 Mar 2014 11:30:22 EST # Added online documentation daemon test and CIS reference for httpdlite on AIX # 4.2.1 Thu 27 Mar 2014 15:05:10 EST # Added NCS test and CIS reference for AIX # 4.2.2 Thu 27 Mar 2014 15:13:04 EST # Added i4ls test and CIS reference of AIX # 4.2.3 Thu 27 Mar 2014 15:45:39 EST # Added serial login test and CIS reference for AIX # 4.2.4 Thu 27 Mar 2014 16:06:59 EST # Added user home directory tests and CIS references for AIX # 4.2.5 Thu 27 Mar 2014 16:16:13 EST # Added /var/adm/sa ownership test and CIS reference for AIX # 4.2.6 Thu 27 Mar 2014 16:30:53 EST # Added snmp and ras permissions test and CIS reference for AIX # 4.2.7 Thu 27 Mar 2014 17:11:37 EST # Added various file/directory permissions tests and CIS references for AIX # 4.2.8 Thu 27 Mar 2014 17:44:09 EST # Added Initial TCP Wrappers test and CIS references for AIX # 4.2.9 Fri 28 Mar 2014 07:52:02 EST # Added code to drive rctcp on AIX # 4.3.0 Fri 28 Mar 2014 08:18:59 EST # Added sendmail test and CIS reference for AIX # 4.3.1 Fri 28 Mar 2014 08:31:37 EST # Added snmp test and CIS reference for AIX # 4.3.2 Fri 28 Mar 2014 08:37:56 EST # Added sendmail disable variable # 4.3.3 Fri 28 Mar 2014 08:46:02 EST # Added dhcpcd test and CIS reference for AIX # 4.3.4 Fri 28 Mar 2014 08:52:12 EST # Added dhcprd test and CIS reference for AIX # 4.3.5 Fri 28 Mar 2014 08:56:33 EST # Added dhcpsd test and CIS reference for AIX # 4.3.6 Fri 28 Mar 2014 09:01:46 EST # Added autoconf6 test and CIS reference for AIX # 4.3.7 Fri 28 Mar 2014 09:14:02 EST # Added gated test and CIS reference for AIX # 4.3.8 Fri 28 Mar 2014 09:56:38 EST # Added mrouted test and CIS reference for AIX # 4.3.9 Fri 28 Mar 2014 10:14:12 EST # Added named test and CIS reference for AIX # 4.3.9 Fri 28 Mar 2014 10:16:12 EST # Added routed test and CIS reference for AIX # 4.4.0 Fri 28 Mar 2014 10:21:13 EST # Added rwhod test and CIS reference for AIX # 4.4.1 Fri 28 Mar 2014 10:26:21 EST # Added timed test and CIS reference for AIX # 4.4.2 Fri 28 Mar 2014 10:29:26 EST # Added dpid2 test and CIS reference for AIX # 4.4.3 Fri 28 Mar 2014 10:31:32 EST # Added hostmibd test and CIS reference for AIX # 4.4.4 Fri 28 Mar 2014 10:32:07 EST # Added snmpdmibd test and CIS reference for AIX # 4.4.5 Fri 28 Mar 2014 10:33:56 EST # Added aixmibd test and CIS reference for AIX # 4.4.6 Fri 28 Mar 2014 10:51:38 EST # Added NPD tests and CIS references for AIX # 4.4.7 Fri 28 Mar 2014 10:57:08 EST # Added .netrc tests and CIS references for AIX # 4.4.8 Fri 28 Mar 2014 10:59:05 EST # Added .rhosts tests and CIS references for AIX # 4.4.9 Fri 28 Mar 2014 12:43:48 EST # Added hosts.equiv tests and CIS references for AIX # 4.5.0 Fri 28 Mar 2014 12:54:51 EST # Added code to drive no on AIX # 4.5.1 Fri 28 Mar 2014 13:33:07 EST # Added network kernel tuning parameter test and CIS references for AIX # 4.5.2 Fri 28 Mar 2014 14:38:14 EST # Added code to drive subserver on AIX # 4.5.3 Fri 28 Mar 2014 14:56:37 EST # Added legacy services tests and CIS references for AIX # 4.5.4 Sat 29 Mar 2014 20:45:37 EST # Added numerous CIS references for Solaris tests # 4.5.5 Sun 30 Mar 2014 09:07:50 EST # Added more CIS references for Solaris tests # 4.5.6 Sun 30 Mar 2014 15:47:53 EST # Added more CIS references for Linux tests and cleaned up some Linux test conditions # 4.5.7 Sun 30 Mar 2014 18:19:19 EST # Added kernel-PAE package check # 4.5.8 Sun 30 Mar 2014 18:46:32 EST # Added various client package tests for Linux # 4.5.9 Sun 30 Mar 2014 20:56:34 EST # Added code to remove talk client on Linux # 4.6.0 Sun 30 Mar 2014 21:03:03 EST # Fixed xinetd test for Linux # 4.6.1 Sun 30 Mar 2014 21:48:42 EST # Added CIS references and updated syslog configuration for Linux # 4.6.2 Sun 30 Mar 2014 22:00:49 EST # Updated syslog and rsyslog test for Linux # 4.6.3 Mon 31 Mar 2014 09:35:36 EST # Added pam_deny and pam_ccred tests for Linux # 4.6.4 Mon 31 Mar 2014 10:01:27 EST # Added inactive user test for Linux # 4.6.5 Mon 31 Mar 2014 10:49:09 EST # Added more CIS references for Linux # 4.6.6 Mon 31 Mar 2014 14:44:00 EST # Added noexec tmpfs test for Linux # 4.6.7 Mon 31 Mar 2014 21:05:17 EST # More CIS references for Linux # 4.6.8 Tue 1 Apr 2014 09:48:55 EST # Added interactive boot test # 4.6.9 Tue 1 Apr 2014 10:13:02 EST # Added kernel-pae test and CIS reference for SuSE Linux # 4.7.0 Tue 1 Apr 2014 13:45:14 EST # Added AppArmour and biosdevname test for SuSE Linux # 4.7.1 Tue 1 Apr 2014 14:49:16 EST # Added SuSEfirewall2 test # 4.7.2 Tue 1 Apr 2014 17:41:27 EST # Added shadow group member test for SuSE Linux # 4.7.3 Tue 1 Apr 2014 18:31:11 EST # Added gdm-autologin PAM check for Solaris 11 # 4.7.4 Tue 1 Apr 2014 19:50:22 EST # Added EEEPROM password test for SPARC # 4.7.5 Wed 2 Apr 2014 12:31:55 EST # Fixed bugs (thanks to Mark Lane for testing) # 4.7.6 Wed 2 Apr 2014 15:13:36 EST # More bug fixes # 4.7.7 Thu 3 Apr 2014 15:05:09 EST # Updated AppArmour test for SuSE Linux # 4.7.8 Sat 12 Apr 2014 13:34:49 EST # Reference updates # 4.7.9 Sat 12 Apr 2014 22:20:43 EST # Reference updates # 4.8.0 Sun 13 Apr 2014 17:40:02 EST # Reference updates and bug fixes # 4.8.1 Sun 13 Apr 2014 21:21:48 EST # Removed duplicate auto logout module # 4.8.2 Fri 25 Apr 2014 12:16:09 EST # Fixed some bugs # 4.8.3 Sun 27 Apr 2014 16:07:34 EST # Fixed audit_system_auth_use_uid # 4.8.4: Tue 6 May 2014 12:42:52 EST # Minor fixes # 4.8.5: Thu 8 May 2014 09:14:24 EST # Fixed cron allow test for Solaris 11, Linux and FreeBSD # 4.8.6: Wed 14 May 2014 13:29:30 EST # Minor updates # 4.8.7: Thu 15 May 2014 12:07:13 EST # Deleted duplicate root group test # 4.8.8: Thu May 29 03:05:01 UTC 2014 # Bug fixes and inital ESXi support (no tests) # 4.8.9: Thu 29 May 2014 16:28:43 EST # Improved scoring and added SNMP and Syslog tests for ESX # 4.9.0: Fri 30 May 2014 08:53:44 EST # Added NTP check for ESXi and made further improvements to scoring # 4.9.1: Fri 30 May 2014 11:37:44 EST # Added signed kernel module test for ESXi # 4.9.2: Fri 30 May 2014 15:23:01 EST # Added shell timeout tests for ESXi # 4.9.3: Fri 30 May 2014 15:40:43 EST # Added Syslog directory test for ESXi # 4.9.4: Fri 30 May 2014 16:48:29 EST # Added software update test for ESXi # 4.9.5: Fri 30 May 2014 18:48:39 EST # Added Managed Object Browser test for ESXi # 4.9.6: Fri 30 May 2014 20:44:33 EST # Added Dvfilter test for ESXi # 4.9.7: Sat 31 May 2014 06:54:25 EST # Added DCUI, SSH and ESXi Shell tests fo ESXi # 4.9.8: Sat 31 May 2014 08:15:56 EST # Added Lockdown check for ESXi # 4.9.9: Sat 31 May 2014 09:47:48 EST # Minor code cleanup # 5.0.0: Wed 11 Jun 2014 18:54:58 EST # Updated license # 5.0.1: Tue 28 Apr 2015 15:05:14 AEST # Removed call to audit_root_account as it was split into several audit_root_* subroutines # 5.0.2: Sat 14 Jan 2017 12:06:37 AEDT # Start adding support for Amazon Linux and added vfat to modprobe check # 5.0.3: Sat 14 Jan 2017 16:22:29 AEDT # Initial Amazon Linux support # 5.0.4: Sat 14 Jan 2017 17:22:34 AEDT # Fixed audit select function # 5.0.5: Sat 14 Jan 2017 19:34:40 AEDT # Fixed code to print module information # 5.0.6: Sat 14 Jan 2017 23:48:24 AEDT # Code cleanup # 5.0.7: Sun 15 Jan 2017 11:11:19 AEDT # Updates for Amazon Linux and Centos / RHEL 7 # 5.0.8: Sun 15 Jan 2017 13:09:27 AEDT # More updates for Amazon Linux and Centos / RHEL 7 # 5.0.9: Sun 15 Jan 2017 13:55:43 AEDT # More updates for Amazon Linux and Centos / RHEL 7 # 5.1.0: Sun 15 Jan 2017 14:17:54 AEDT # More updated for Amazon Linux and Centos / RHEL 7 # 5.1.1: Sun 15 Jan 2017 14:57:17 AEDT # Documentation cleanup # 5.1.2: Sun 15 Jan 2017 16:09:52 AEDT # More updates for Amazon Linux and Centos / RHEL 7 # 5.1.3: Sun 15 Jan 2017 16:18:28 AEDT # Bug fixes # 5.1.4: Mon 16 Jan 2017 07:38:08 AEDT # Bug fixes # 5.1.5: Mon 16 Jan 2017 07:55:34 AEDT # Fix for Amazon Linux # 5.1.6: Mon 16 Jan 2017 08:16:55 AEDT # Bug fixes # 5.1.7: Mon 16 Jan 2017 09:18:43 AEDT # Cleaned up reporting # 5.1.8: Mon 16 Jan 2017 17:15:21 AEDT # Fixed code to use . rather than source on Ubuntu and Debian (sh is actually bash) # 5.1.9: Tue 17 Jan 2017 20:13:43 AEDT # Updated Linux package handling code # 5.2.0: Wed 18 Jan 2017 08:39:55 AEDT # Initial code for AWS Foundation Security audit # 5.2.1: Wed 18 Jan 2017 14:47:16 AEDT # Added AWS credentials check # 5.2.2: Wed 18 Jan 2017 15:49:35 AEDT # Added AWS credential rotation check # 5.2.3: Wed 18 Jan 2017 18:56:54 AEDT # Added AWS password policy check # 5.2.4: Wed 18 Jan 2017 20:33:11 AEDT # Added AWS root account MFA check # 5.2.5: Wed 18 Jan 2017 21:28:14 AEDT # Added AWS user policy check # 5.2.6: Thu 19 Jan 2017 07:34:48 AEDT # Added AWS support role check # 5.2.7: Thu 19 Jan 2017 09:05:08 AEDT # Added AWS access keys check # 5.2.8: Thu 19 Jan 2017 10:15:18 AEDT # Added AWS full administrative privileges check # 5.2.9: Thu 19 Jan 2017 10:58:16 AEDT # Added AWS CloudTrail MultiRegion check # 5.3.0: Thu 19 Jan 2017 11:14:20 AEDT # Added AWS CloudTrail LogFileValidation check # 5.3.1: Thu 19 Jan 2017 11:47:33 AEDT # Added AWS CloudTrail bucket permissions check # 5.3.2: Thu 19 Jan 2017 16:59:12 AEDT # Added AWS IAM Master / Manager account check # 5.3.3: Thu 19 Jan 2017 17:54:06 AEDT # Fixed various AWS bugs # 5.3.4: Thu 19 Jan 2017 21:40:00 AEDT # Added AWS CloudTrail bucket policy check # 5.3.5: Thu 19 Jan 2017 22:14:38 AEDT # Added AWS CloudTrail CloudWatch Logs integration check # 5.3.6: Thu 19 Jan 2017 23:02:54 AEDT # Added initial support for AWS Config check # 5.3.7: Thu 19 Jan 2017 23:13:12 AEDT # Added AWS CloudTrail S3 Bucket logging check # 5.3.8: Thu 19 Jan 2017 23:24:30 AEDT # Added AWS CloudTrail KMS Key check # 5.3.9: Fri 20 Jan 2017 08:24:56 AEDT # Added AWS Key check # 5.4.0: Fri 20 Jan 2017 10:03:02 AEDT # Added AWS VPC peering check # 5.4.1: Fri 20 Jan 2017 13:19:36 AEDT # Added Inbound / Outbond check for AWS Security Groups # 5.4.2: Fri 20 Jan 2017 14:33:57 AEDT # Added AWS VPC flow log check # 5.4.3: Fri 20 Jan 2017 16:13:34 AEDT # Added AWS Security Group check for open SSH / RDP ports # 5.4.4: Fri 20 Jan 2017 17:28:52 AEDT # Added initial AWS SNS checks # 5.4.5: Fri 20 Jan 2017 19:38:09 AEDT # Added initial AWS monitoring checks # 5.4.6: Fri 20 Jan 2017 20:14:43 AEDT # Added AWS alarm and subscriber checks # 5.4.7: Fri 20 Jan 2017 20:41:44 AEDT # Added AWS IAM alarm and subscriber checks # 5.4.8: Fri 20 Jan 2017 22:14:27 AEDT # Added AWS CloudTrail, Console, Key, S3, Config, NACL, Security Group, Gateway, Route and VPC alarm and subscriber checks # 5.4.9: Sat 21 Jan 2017 08:41:04 AEDT # Added fix information for AWS Access Keys # 5.5.0: Tue 24 Jan 2017 05:20:07 AEDT # Cleaned up AWS CloudTrail checks # 5.5.1: Tue 24 Jan 2017 16:22:48 AEDT # Added some fix information for VPC checks # 5.5.2: Tue 24 Jan 2017 16:47:11 AEDT # Added some fix information for SNS check # 5.5.3: Tue 24 Jan 2017 17:15:33 AEDT # Updated AWS CloudTrail Key fix information # 5.5.4: Tue 24 Jan 2017 17:26:25 AEDT # Added some fix information for S3 bucket logging # 5.5.5: Tue 24 Jan 2017 17:29:39 AEDT # Added some fix information for AWS Config # 5.5.6: Tue 24 Jan 2017 17:38:19 AEDT # Added some fix information for CloudTrail bucket permissions # 5.5.7: Tue 24 Jan 2017 19:58:17 AEDT # Added initial ability to set AWS region on command line # 5.5.8: Tue 24 Jan 2017 21:09:08 AEDT # Added additional support for setting AWS region # 5.5.9: Tue 24 Jan 2017 21:25:13 AEDT # Added initial support for AWS recommendations # 5.6.0: Tue 24 Jan 2017 22:35:11 AEDT # Added AWS IAM SSH Public Keys check # 5.6.1: Tue 24 Jan 2017 22:45:17 AEDT # Added AWS IAM empty group check # 5.6.2: Wed 25 Jan 2017 06:27:00 AEDT # Added check for expired AWS certificates # 5.6.3: Wed 25 Jan 2017 06:40:16 AEDT # Added check for inactive AWS IAM accounts # 5.6.4: Wed 25 Jan 2017 07:19:13 AEDT # Added check for AWS Route53 Domain renewals # 5.6.5: Wed 25 Jan 2017 07:31:24 AEDT # Added check for AWS Route53 Domain expiration # 5.6.6: Wed 25 Jan 2017 08:32:35 AEDT # Added check for AWS Route53 Zone SPF records # 5.6.7: Wed 25 Jan 2017 08:40:14 AEDT # Added check for AWS Route53 Domain Transfer Lock # 5.6.8: Wed 25 Jan 2017 12:52:00 AEDT # Added check for AWS instance image ID owner # 5.6.9: Wed 25 Jan 2017 17:47:28 AEDT # Added check for number of AWS EIPs consumer # 5.7.0: Wed 25 Jan 2017 18:21:39 AEDT # Added check for AWS instances using the default security group # 5.7.1: Wed 25 Jan 2017 18:46:14 AEDT # Added check for AWS EC2-Classic instances # 5.7.2: Wed 25 Jan 2017 19:34:59 AEDT # Added check against recommended Instance name # 5.7.3: Wed 25 Jan 2017 20:49:54 AEDT # Added check for AWS instance termination protection # 5.7.4: Wed 25 Jan 2017 21:20:52 AEDT # Added check to see if instances have IAM profiles # 5.7.5: Thu 26 Jan 2017 04:41:19 AEDT # Added check for publicly shared AWS AMIs # 5.7.6: Thu 26 Jan 2017 05:42:37 AEDT # Added check against recommended Security Group name # 5.7.7: Thu 26 Jan 2017 09:09:47 AEDT # Split out AWS VPC and SG checks # 5.7.8: Thu 26 Jan 2017 09:17:26 AEDT # Added check for AWS SGs with open CIFS ports # 5.7.9: Thu 26 Jan 2017 09:22:07 AEDT # Added check for AWS SGs with open DNS ports # 5.8.0: Thu 26 Jan 2017 09:51:13 AEDT # Added check for AWS SGs with open FTP ports # 5.8.1: Thu 26 Jan 2017 10:03:33 AEDT # Added check for AWS SGs with various open ports # 5.8.2: Thu 26 Jan 2017 11:00:34 AEDT # Added check for AWS SGs with open MongoDB ports # 5.8.3: Thu 26 Jan 2017 11:09:27 AEDT # Added check for AWS SGs with open RPC ports # 5.8.4: Thu 26 Jan 2017 11:48:10 AEDT # Added check for AWS SGs with open ICMP # 5.8.5: Thu 26 Jan 2017 11:51:56 AEDT # Added check for AWS SGs with open SMTP # 5.8.6: Thu 26 Jan 2017 11:55:15 AEDT # Added check for AWS SGs with open Telnet # 5.8.7: Thu 26 Jan 2017 12:20:11 AEDT # Added check for AWS users with attached policies # 5.8.8: Thu 26 Jan 2017 14:02:54 AEDT # Added check for AWS ES domains being publicly accessible # 5.8.9: Thu 26 Jan 2017 14:27:20 AEDT # Added check for AWS ES domains having IP access policy # 5.9.0: Thu 26 Jan 2017 14:43:32 AEDT # Added check for AWS ES domains having dedicated master nodes # 5.9.1: Thu 26 Jan 2017 14:51:13 AEDT # Added check for AWS ES domains using General Purpose SSD to be cost effective # 5.9.2: Thu 26 Jan 2017 15:25:04 AEDT # Added check for AWS ES domains being cross zone aware # 5.9.3: Thu 26 Jan 2017 16:03:54 AEDT # Added more tag checks for AWS EC2 instances # 5.9.4: Thu 26 Jan 2017 20:54:23 AEDT # Added check for empty DynamoDB tables to be cost effective # 5.9.5: Thu 26 Jan 2017 21:19:06 AEDT # Added check for AWS ELB logging being enabled # 5.9.6: Thu 26 Jan 2017 22:54:21 AEDT # Added check for AWS ELB connection draining being enabled # 5.9.7: Thu 26 Jan 2017 23:08:23 AEDT # Added check for AWS ELB cross zone balancing being enabled # 5.9.8: Fri 27 Jan 2017 07:07:37 AEDT # Added check for AWS ELB using deprecated ciphers # 5.9.9: Fri 27 Jan 2017 07:38:05 AEDT # Added check for AWS ELB using deprecated protocols # 6.0.0: Fri 27 Jan 2017 08:20:44 AEDT # Added check for AWS ELB using HTTP rather than HTTPS # 6.0.1: Fri 27 Jan 2017 08:32:32 AEDT # Added check for AWS ELB having at least 2 instances # 6.0.2: Fri 27 Jan 2017 08:48:57 AEDT # Added check for AWS ELB SGs being open on port 80 # 6.0.3: Fri 27 Jan 2017 09:22:00 AEDT # Added check for out of service AWS ELB instances # 6.0.4: Fri 27 Jan 2017 09:33:32 AEDT # Added check for unencrypted AWS EC2 volumes # 6.0.5: Fri 27 Jan 2017 13:19:21 AEDT # Added check for AWS EC2 volume names # 6.0.6: Fri 27 Jan 2017 18:04:39 AEDT # Added check for AWS EC2 snapshots older than 30 days # 6.0.7: Fri 27 Jan 2017 19:13:08 AEDT # Added check for AWC EC2 unattached volumes to be cost effective # 6.0.8: Fri 27 Jan 2017 19:37:26 AEDT # Added check for AWC VPC exposed endpoints # 6.0.9: Fri 27 Jan 2017 21:42:09 AEDT # Added check for AWS VPC names # 6.1.0: Sat 28 Jan 2017 08:16:46 AEDT # Added check for AWS VPC / VPN redundancy # 6.1.1: Sat 28 Jan 2017 09:00:59 AEDT # Added check for AWS S3 bucket grants # 6.1.2: Sat 28 Jan 2017 09:05:50 AEDT # Added check for AWS S3 bucket logging # 6.1.3: Sat 28 Jan 2017 09:13:45 AEDT # Added check for AWS S3 bucket versioning # 6.1.4: Sat 28 Jan 2017 14:06:32 AEDT # Added check for AWS SES and DKIM # 6.1.5: Sat 28 Jan 2017 14:45:31 AEDT # Added check for AWS RDS auto minor version upgrade # 6.1.6: Sat 28 Jan 2017 15:15:43 AEDT # Added check for AWS RDS automated backups # 6.1.7: Sat 28 Jan 2017 16:51:40 AEDT # Added check for AWS RDS encryption # 6.1.8: Sat 28 Jan 2017 17:06:52 AEDT # Added check for AWS RDS having Multi-AZ enabled # 6.1.9: Sat 28 Jan 2017 19:32:15 AEDT # Added check for AWS RDS Security Groups # 6.2.0: Sat 28 Jan 2017 20:39:56 AEDT # Added check for AWS RDS using KMS key # 6.2.1: Sat 28 Jan 2017 21:08:09 AEDT # Added check for AWS RDS using General Purpose SSD to be cost effective # 6.2.2: Sat 28 Jan 2017 21:26:07 AEDT # Added check for AWS RDS instances being on a public facing subnet # 6.2.3: Sat 28 Jan 2017 21:45:29 AEDT # Added check for AWS RDS instances using default master username # 6.2.4: Sun 29 Jan 2017 11:40:24 AEDT # Added check for AWS RDS registered instances expiring # 6.2.5: Sun 29 Jan 2017 11:54:14 AEDT # Added check for AWS RDS backup retention period # 6.2.6: Sun 29 Jan 2017 12:44:23 AEDT # Added check for AWS EC2 EBS volumes having KMS keys # 6.2.7: Sun 29 Jan 2017 15:31:20 AEDT # Added check for AWS EC2 EBS volume snapshots being taken # 6.2.8: Sun 29 Jan 2017 17:16:24 AEDT # Added check for AWS CloudTrail recording global events # 6.2.9: Sun 29 Jan 2017 19:03:52 AEDT # Added check for AWS inactive KMS keys # 6.3.0: Sun 29 Jan 2017 19:03:52 AEDT # Added check for AWS SNS topic being publicly accessible # 6.3.1: Sun 29 Jan 2017 20:02:57 AEDT # Added check for AWS CloudFormation stacks using SNS # 6.3.2: Sun 29 Jan 2017 20:30:55 AEDT # Added check for AWS CloudFormation stacks having policies # 6.3.3: Sun 29 Jan 2017 20:49:28 AEDT # Added check for AWS ElastiCache having HA enabled # 6.3.4: Sun 29 Jan 2017 21:06:57 AEDT # Added check for AWS ElastiCache reserved instances expiring # 6.3.5: Sun 29 Jan 2017 21:23:07 AEDT # Added check for AWS Cloudfront WAF integration being enabled # 6.3.6: Sun 29 Jan 2017 21:31:31 AEDT # Added check for AWS Cloudfront logging being enabled # 6.3.7: Sun 29 Jan 2017 21:38:47 AEDT # Added check for AWS Cloudfront using deprecate SSL version # 6.3.8: Sun 29 Jan 2017 21:43:31 AEDT # Added check for AWS Cloudfront using HTTP only # 6.3.9: Sun 29 Jan 2017 22:08:20 AEDT # Added check for AWS CloudWatch alarm for EC2 instance changes # 6.4.0: Sun 29 Jan 2017 22:22:11 AEDT # Added check for AWS CloudWatch alarm for EC2 instance size changes # 6.4.1: Mon 30 Jan 2017 08:13:20 AEDT # Added check for AWS Redshift upgrades being enabled # 6.4.2: Mon 30 Jan 2017 08:36:14 AEDT # Added check for AWS Redshift logging being enabled # 6.4.3: Mon 30 Jan 2017 08:44:03 AEDT # Added check for AWS Redshift encryption being enabled # 6.4.4: Mon 30 Jan 2017 08:50:04 AEDT # Added check for AWS Redshift using KMS keys # 6.4.5: Mon 30 Jan 2017 09:12:42 AEDT # Added check for AWS Redshift using EC2-VPC domains rather than EC2-Classic # 6.4.6: Mon 30 Jan 2017 09:34:38 AEDT # Added check for AWS Redshift paramter groups requiring SSL # 6.4.7: Mon 30 Jan 2017 09:47:58 AEDT # Added check for AWS Redshift being publicly available # 6.4.8: Mon 30 Jan 2017 10:11:21 AEDT # Added check for AWS Redshift reserved instances about to expire # 6.4.9: Tue 31 Jan 2017 14:55:55 AEDT # Added check for AWS Inspector being used # 6.5.0: Tue 31 Jan 2017 16:39:08 AEDT # Added check for AWS Inspector assessment recommendation (CVEs) # 6.5.1: Tue 7 Feb 2017 14:34:39 AEDT # Added initial support for Docker # 6.5.2: Tue 7 Feb 2017 16:59:27 AEDT # Added additional Docker support # 6.5.3: Tue 7 Feb 2017 17:37:13 AEDT # Added Docker network bridge test # 6.5.4: Wed 8 Feb 2017 07:43:30 AEDT # Added more Docker tests and updated SSH TCP forwarding test # 6.5.5: Wed 8 Feb 2017 08:09:14 AEDT # Fixed Docker daemon test # 6.5.6: Wed 8 Feb 2017 08:17:15 AEDT # Added Docker user namespace support test # 6.5.7: Wed 8 Feb 2017 08:32:00 AEDT # Added Docker daemon storage option and authorisation plugin checks # 6.5.8: Wed 8 Feb 2017 08:37:12 AEDT # Added additional Docker logging tests # 6.5.9: Wed 8 Feb 2017 08:46:12 AEDT # Added Docker legacy registry check # 6.6.0: Wed 8 Feb 2017 08:48:46 AEDT # Added Docker liver restore check # 6.6.1: Wed 8 Feb 2017 08:54:36 AEDT # Added Docker userland proxy test # 6.6.2: Wed 8 Feb 2017 08:57:18 AEDT # Added Docker encrypted network traffic check # 6.6.3: Wed 8 Feb 2017 08:59:50 AEDT # Added Docker seccomp profile test # 6.6.4: Wed Feb 8 09:23:05 AEDT 2017 # Added Docker swarm unlock key test # 6.6.5: Wed 8 Feb 2017 10:16:35 AEDT # Added Docker file permission tests # 6.6.6: Wed 8 Feb 2017 10:43:45 AEDT # Added Docker container user test # 6.6.7: Wed 8 Feb 2017 11:53:36 AEDT # Added Docker Healthcheck test # 6.6.8: Wed 8 Feb 2017 12:33:33 AEDT # Added Docker AppArmor test # 6.6.9: Wed 8 Feb 2017 12:46:13 AEDT # Added Docker SELinux test # 6.7.0: Wed 8 Feb 2017 14:41:52 AEDT # Added Docker capabilities test # 6.7.1: Wed 8 Feb 2017 14:48:15 AEDT # Added Docker privileged container check # 6.7.2: Wed 8 Feb 2017 15:11:17 AEDT # Added Docker host network namespace check # 6.7.3: Wed 8 Feb 2017 15:26:33 AEDT # Added Docker memory usage limit test # 6.7.4: Wed 8 Feb 2017 17:17:58 AEDT # Initial Docker code cleanup # 6.7.5: Wed 8 Feb 2017 17:50:16 AEDT # Additional Docker code cleanup # 6.7.6: Wed 8 Feb 2017 17:57:59 AEDT # Added Docker Memory and CpuShares tests # 6.7.7: Wed 8 Feb 2017 19:04:24 AEDT # Added Docker Ports check and cleaned up code # 6.7.8: Wed 8 Feb 2017 19:24:39 AEDT # More Docker fixes # 6.7.9: Wed 8 Feb 2017 19:38:44 AEDT # Added Docker PidMode check # 6.8.0: Wed 8 Feb 2017 19:41:46 AEDT # Added Docker IpcMode check # 6.8.1: Wed 8 Feb 2017 19:57:04 AEDT # Added Docker Devices check # 6.8.2: Wed 8 Feb 2017 20:02:58 AEDT # Added Docker Ulimits check # 6.8.3: Wed 8 Feb 2017 20:15:10 AEDT # Added Docker mount propagation check # 6.8.4: Wed 8 Feb 2017 20:20:25 AEDT # Added Docker UTSMode check # 6.8.5: Wed 8 Feb 2017 21:58:01 AEDT # Added Docker exec commands with privileged option check # 6.8.6: Wed 8 Feb 2017 22:45:04 AEDT # Cleaned up Docker tests # 6.8.7: Wed 8 Feb 2017 22:56:11 AEDT # Added Docker exec commands with user option check # 6.8.8: Wed 8 Feb 2017 22:59:43 AEDT # Added Docker CgroupParent test # 6.8.9: Wed 8 Feb 2017 23:09:53 AEDT # Added Docker SecurityOpt tests # 6.9.0: Wed 8 Feb 2017 23:28:37 AEDT # Added Docker Health test # 6.9.1: Wed 8 Feb 2017 23:45:46 AEDT # Added Docker default bridge test # 6.9.2: Wed 8 Feb 2017 23:49:04 AEDT # Added Docker UsernsMode test # 6.9.3: Wed 8 Feb 2017 23:59:47 AEDT # Added Docker socket mount test # 6.9.4: Thu 9 Feb 2017 00:18:07 AEDT # Added option to list Docker reports # 6.9.5: Thu 9 Feb 2017 00:36:30 AEDT # Updated GRUB test # 6.9.6: Thu Feb 9 06:53:33 AEDT 2017 # Code cleanup and bug fixes # 6.9.7: Thu 9 Feb 2017 09:12:03 AEDT # Bug fixes and documenation updates # 6.9.8: Thu 9 Feb 2017 09:37:36 AEDT # Bug fixes and documenation updates # 6.9.9: Thu 9 Feb 2017 10:51:58 AEDT # Bug fixes and documenation updates # 7.0.0: Thu 9 Feb 2017 11:09:01 AEDT # Bug fixes and documenation updates # 7.0.1: Thu 9 Feb 2017 15:37:09 AEDT # Updated documentation # 7.0.2: Fri 10 Feb 2017 00:23:29 AEDT # Updates for OS X 10.12 # 7.0.3: Fri 10 Feb 2017 08:25:51 AEDT # Bug fixes and documentation updates # 7.0.4: Fri 10 Feb 2017 11:52:39 AEDT # Code cleanup # 7.0.5: Fri 10 Feb 2017 12:28:13 AEDT # Added screen sharing test for OS X # 7.0.6: Fri 10 Feb 2017 12:50:59 AEDT # Added remote login check for OS X # 7.0.7: Fri 10 Feb 2017 13:44:56 AEDT # Added sleep check for OS X and updated documentation # 7.0.8: Fri 10 Feb 2017 14:05:20 AEDT # Code cleanup # 7.0.9: Sat 11 Feb 2017 07:39:17 AEDT # Code cleanup # 7.1.0: Sat 11 Feb 2017 09:52:05 AEDT # Updated SSH support to include sandbox for privilege separation # 7.1.1: Sat 11 Feb 2017 11:56:22 AEDT # Added Java test for OS X # 7.1.2: Sat 11 Feb 2017 12:21:17 AEDT # Added system log test for OS X # 7.1.3: Sat 11 Feb 2017 12:34:06 AEDT # Added addition system log tests for OS X and updated documentation # 7.1.4: Sat 11 Feb 2017 12:50:18 AEDT # Added addition system log tests for OS X and updated documentation # 7.1.5: Sat 11 Feb 2017 12:58:07 AEDT # Added wireless check for OS X # 7.1.6: Sat 11 Feb 2017 13:16:16 AEDT # Added NFS daemon check for OS X # 7.1.7: Sat 11 Feb 2017 15:44:55 AEDT # Added Application permission checks for OS X # 7.1.8: Sat 11 Feb 2017 16:33:48 AEDT # Updated OS X password policy test # 7.1.9: Sat 11 Feb 2017 17:18:07 AEDT # Updated OS X password policy test # 7.2.0: Sat 11 Feb 2017 17:39:07 AEDT # Updated OS X keychain check # 7.2.1: Sat 11 Feb 2017 17:50:45 AEDT # Updated OS X login policy test and documentation # 7.2.2: Sat 11 Feb 2017 18:18:10 AEDT # Added system preferences check for OS X # 7.2.3: Sat 11 Feb 2017 20:36:05 AEDT # Added System Integrity Protection test for OS X # 7.2.4: Sat 11 Feb 2017 21:39:02 AEDT # Updated documentation # 7.2.5: Sun Feb 12 13:26:29 AEDT 2017 # Code cleanup # 7.2.6: Sat 9 Sep 2017 17:44:38 AEST # Cleaned up command line argument handling # 7.2.7: Wed 27 Dec 2017 07:55:29 AEDT # Fixed uname and stat on OS X # 7.2.8: Sat 9 Feb 2019 13:09:58 AEDT # Fixed a bug with chkconfig on Centos # 7.2.9: Sun 21 Apr 2019 11:19:00 AEST # Fixed Java version check and some other bugs # 7.3.0: Sun 21 Apr 2019 13:06:51 AEST # Added initial code for detecting virtual platform and fixed separate filesystems check # 7.3.1: Sun Apr 21 15:48:28 AEST 2019 # Cleanup and bug fixes # 7.3.2: Sun 21 Apr 2019 16:25:36 AEST # Fixed bug with sulogin check # 7.3.3: Sun 21 Apr 2019 17:40:10 AEST # Fixed bug with file value check and check values starting in hyphens # 7.3.4: Sun 21 Apr 2019 18:16:35 AEST # Initial bug fix for X Windows System package group being installed # 7.3.5: Sun 21 Apr 2019 21:11:20 AEST # Added group package check # 7.3.6: Tue 23 Apr 2019 12:06:07 AEST # Fixed bug with module check # 7.3.7: Tue 23 Apr 2019 14:24:39 AEST # Made code more portable # 7.3.8: Tue 23 Apr 2019 15:14:52 AEST # More fixes # 7.3.9: Tue 23 Apr 2019 18:37:02 AEST # Added initial docker test matrix # 7.4.0: Tue 23 Apr 2019 19:16:20 AEST # More bug fixes # 7.4.1: Tue 23 Apr 2019 20:36:25 AEST # Improved handling for beta releases of Red Hat Linux # 7.4.2: Tue 23 Apr 2019 20:44:23 AEST # Added file check to securetty test # 7.4.3: Tue 23 Apr 2019 22:04:08 AEST # Initial Kubernetes support # 7.4.4: Wed 24 Apr 2019 07:24:28 AEST # Added support of hyphens in parameter names in file value checks # 7.4.5: Wed 24 Apr 2019 08:15:38 AEST # Added additional kubernetes checks # 7.4.6: Wed 24 Apr 2019 12:10:50 AEST # Added additional kubernetes checks # 7.4.7: Wed 24 Apr 2019 16:38:49 AEST # Minor cleanup # 7.4.8: Wed 24 Apr 2019 18:27:05 AEST # Updated check file value function # 7.4.9: Wed 24 Apr 2019 20:39:39 AEST # Added additional kubernetes checks # 7.5.0: Tue 11 Jun 2019 14:58:46 AEST # Execshield fix # 7.5.1: Tue 30 Jul 2019 21:54:54 AEST # Fixes for Debian # 7.5.2: Wed 31 Jul 2019 09:48:02 AEST # Additional fix for Debian unstable # 7.5.3: Wed 31 Jul 2019 20:36:53 AEST # Fixes for date on Linux # 7.5.4: Wed 22 Jan 2020 09:33:40 AEDT # Bug fixes and initial ansbile output # 7.5.5: Wed 22 Jan 2020 10:13:08 AEDT # Bug fixes # 7.5.6: Wed 22 Jan 2020 14:13:22 AEDT # Bug fixes and code cleanup # 7.5.7: Wed 22 Jan 2020 20:36:05 AEDT # Added more ansible stanzas # 7.5.8: Wed 22 Jan 2020 21:43:05 AEDT # Bug fixes and code cleanup # 7.5.9: Thu 23 Jan 2020 12:05:26 AEDT # Added more ansible stanzas # 7.6.0: Thu 23 Jan 2020 15:07:16 AEDT # Added more ansible stanzas # 7.6.1: Tue 18 Feb 2020 08:09:12 AEDT # Fixes and improvements as suggesting in issue 36 # 7.6.2: Tue Feb 18 09:17:17 AEDT 2020 # Fixes for RedHat/Centos 8.x using chrony by default as suggested in issue 35 # 7.6.3: Sun 3 May 2020 08:48:13 AEST # Fixed bug with filesystem partitions check # 7.6.4: Sun 3 May 2020 10:53:34 AEST # Formating cleanup # 7.6.5: Sun 03 May 2020 12:19:19 AEST # Added in function to check_file_value to cater for multiple parameters in a line # 7.6.6: Sun 03 May 2020 13:13:14 AEST # Ansible output tweaks # 7.6.7: Sun 03 May 2020 14:34:48 AEST # More ansible output tweaks # 7.6.8: Mon 04 May 2020 12:01:58 AEST # More ansible output tweaks # 7.6.9: Mon 18 May 2020 19:25:17 AEST # More Apache support # 7.7.0: Wed 16 Sep 2020 09:08:19 AEST # Fix for filesystem searches on Linux # 7.7.1: Wed 16 Sep 2020 21:54:39 AEST # Removed elfsign # 7.7.2: Fri 18 Sep 2020 22:58:52 AEST # Fixed duplicate options # 7.7.3: Sat 19 Sep 2020 21:53:54 AEST # Fix big with AIX Retry Limit code # 7.7.4: Sun 20 Sep 2020 17:54:08 AEST # Fixed AWS password policy module # 7.7.5: Thu 22 Apr 2021 15:15:54 AEST # Cleaned up linux service check code as per issue #37 # 7.7.6: Thu 22 Apr 2021 16:32:24 AEST # Added code to deal with issue #61 # 7.7.7: Mon 31 Jan 2022 15:56:28 AEDT # Updated security banner based on suggestion from Mark Lane so it can be grepped out easier # 7.7.8: Fri 23 Sep 2022 12:19:00 AEST # Updated check for tally2 PAM module which has been replaced with faillock PAM module in Ubuntu 22.04 # 7.7.9: Fri 23 Sep 2022 17:00:49 AEST # Added check for apport service on Ubuntu 22.04 # 7.8.0: Fri 23 Sep 2022 17:53:12 AEST # Fixed AppArmor check for Ubuntu # 7.8.1: Sat 24 Sep 2022 19:10:14 AEST # Added grub check to Apparmor check # 7.8.2: Sun 25 Sep 2022 08:26:46 AEST # Added grub config/menu file check to Apparmor test # 7.8.3: Sun 25 Sep 2022 15:39:50 AEST # Added gnome defaults check for GDM3 # 7.8.4: Sun 25 Sep 2022 17:05:31 AEST # Added initial code for gsettings function # 7.8.5: Sun 25 Sep 2022 17:11:38 AEST # Fixed bug with apparmor module # 7.8.6: Sun 25 Sep 2022 18:42:04 AEST # Added GDM lock check for Linux # 7.8.7: Sun 25 Sep 2022 21:17:32 AEST # Updated GDM lock check for Linux # 7.8.8: Mon 26 Sep 2022 13:38:37 AEST # Updated GDM lock check for Linux # 7.8.9: Mon 26 Sep 2022 14:39:14 AEST # Added Gnome automount check # 7.9.0: Mon 26 Sep 2022 14:53:17 AEST # Added Gnome autorun check # 7.9.1: Mon 26 Sep 2022 15:10:43 AEST # Updated Gnome autorun check and added Gnome XDMCP check # 7.9.2: Mon 26 Sep 2022 16:52:46 AEST # Fixed prelink and aide checks # 7.9.3: Mon 26 Sep 2022 20:18:21 AEST # Added PAE/NX check # 7.9.4: Tue 27 Sep 2022 10:48:50 AEST # Added exim check # 7.9.5: Tue 27 Sep 2022 10:59:19 AEST # Added wireless check for Linux # 7.9.6: Tue 27 Sep 2022 11:26:50 AEST # Added some UFW checks for Ubuntu Linux # 7.9.7: Tue 27 Sep 2022 11:47:58 AEST # Added audispd-plugins package check # 7.9.8: Wed 28 Sep 2022 20:20:02 AEST # Added grub check for audit flag # 7.9.9: Thu 29 Sep 2022 04:42:26 AEST # Added audit log size check # 8.0.0: Thu 29 Sep 2022 04:56:18 AEST # Fixed audit max log file size # 8.0.1: Thu 29 Sep 2022 05:11:57 AEST # Added faillock to auditing # 8.0.2: Thu 29 Sep 2022 07:23:59 AEST # Added additional checks to system accounting/auditing # 8.0.3: Thu 29 Sep 2022 13:42:08 AEST # Added auditd log_group check # 8.0.4: Thu 29 Sep 2022 14:59:40 AEST # Added additional aide checks # 8.0.5: Thu 29 Sep 2022 16:17:53 AEST # Various updates to system logging and auditing checks # 8.0.6: Sat 1 Oct 2022 14:22:20 AEST # Added check for audit log of running command as another user # 8.0.7: Sat 1 Oct 2022 14:28:36 AEST # Added sudo check to audit # 8.0.8: Sat 1 Oct 2022 14:40:46 AEST # Added check for auditing chchon # 8.0.9: Fri 27 Oct 2023 12:53:20 AEDT # Moved home directory check to be a part of filesystem check option # 8.1.0: Fri Oct 27 18:55:59 AEDT 2023 # Bug fixes for aide check # 8.1.1: Fri Oct 27 19:11:38 AEDT 2023 # Bug fix for apparmor check # 8.1.2: Fri Oct 27 19:15:46 AEDT 2023 # Bug fix for OS X defaults check # 8.1.3: Fri Oct 27 19:18:29 AEDT 2023 # Bug fixes for auditd check # 8.1.4: Fri Oct 27 19:34:00 AEDT 2023 # Bug fixes # 8.1.5: Sat Oct 28 08:25:51 AEDT 2023 # Added check for iptables # 8.1.6: Sat Oct 28 08:31:48 AEDT 2023 # Added check for nmcli # 8.1.7: Sat Oct 28 15:59:00 AEDT 2023 # Added non root user check for reading shadow file # 8.1.8: Sat Oct 28 17:16:46 AEDT 2023 # Added more checks for when not running as root # 8.1.9: Sat 28 Oct 2023 22:53:06 AEDT # Added addition shoftware update checks for macOS Sonoma # 8.2.0: Sat 28 Oct 2023 22:56:29 AEDT # Added keychain sync test for macOS Sonoma # 8.2.1: Sun 29 Oct 2023 07:23:04 AEDT # Fixed issue with OS version/release handling # 8.2.2: Sun 29 Oct 2023 12:47:48 AEDT # Documentation cleanup # 8.2.3: Sun 29 Oct 2023 13:18:06 AEDT # Added Air Drop check # 8.2.4: Sun 29 Oct 2023 13:48:36 AEDT # Added Air Play Receiver check # 8.2.5: Sun 29 Oct 2023 13:52:09 AEDT # Documentation fixes # 8.2.6: Sun 29 Oct 2023 14:17:47 AEDT # Updates for MacOS Sonoma # 8.2.7: Sun 29 Oct 2023 14:29:02 AEDT # Documentation updates # 8.2.8: Sun 29 Oct 2023 15:09:04 AEDT # Added MacOS check for asset caching # 8.2.9: Sun 29 Oct 2023 20:48:01 AEDT # Added MacOS check for media sharing # 8.3.0: Sun 29 Oct 2023 21:05:10 AEDT # Added additional MacOS check for bluetooth sharing # 8.3.1: Sun 29 Oct 2023 21:31:22 AEDT # Added MacOS Time Machine check # 8.3.2: Sun 29 Oct 2023 21:52:39 AEDT # Added additional MacOS wireless check # 8.3.3: Sun 29 Oct 2023 21:59:28 AEDT # Added additional MacOS wireless check # 8.3.4: Mon 30 Oct 2023 07:16:19 AEDT # Added MacOS Siri checks # 8.3.5: Mon 30 Oct 2023 14:46:34 AEDT # Added MacOS Location Services check # 8.3.6: Mon 30 Oct 2023 16:09:37 AEDT # Added MacOS defaults function to handle user defaults # 8.3.7: Mon 30 Oct 2023 16:11:53 AEDT # Bug fixes # 8.3.8: Mon 30 Oct 2023 16:19:09 AEDT # Added additional location services check # 8.3.9: Mon 30 Oct 2023 16:59:08 AEDT # Added MacOS Usage data check # 8.4.0: Mon 30 Oct 2023 17:14:08 AEDT # Added MacOS Ad Tracking check and updated test feedback # 8.4.1: Mon 30 Oct 2023 20:35:54 AEDT # Updated documentation # 8.4.2: Mon 30 Oct 2023 20:49:28 AEDT # Added MacOS Lockdown check # 8.4.3: Mon 30 Oct 2023 21:11:38 AEDT # Added MacOS screen corner setting check # 8.4.4: Mon 30 Oct 2023 21:51:34 AEDT # Added MacOS universal control check # 8.4.5: Tue 31 Oct 2023 10:31:22 AEDT # Added additional MocOS sleep checks for Intel # 8.4.6: Tue 31 Oct 2023 10:37:41 AEDT # Added additional MocOS sleep checks for Apple Silicon # 8.4.7: Tue 31 Oct 2023 10:45:58 AEDT # Added filevault check to sleep checks # 8.4.8: Tue 31 Oct 2023 10:53:13 AEDT # Added powernap check to sleep checks # 8.4.9: Tue 31 Oct 2023 13:12:55 AEDT # Added screen idle time check # 8.5.0: Tue 31 Oct 2023 13:35:22 AEDT # Updated documentation # 8.5.1: Tue 31 Oct 2023 14:12:38 AEDT # Added Touch ID checks # 8.5.2: Tue 31 Oct 2023 14:20:28 AEDT # Documentation updates # 8.5.3: Wed 1 Nov 2023 13:57:00 AEDT # Added MacOS check sysadminctl function # 8.5.4: Wed 1 Nov 2023 16:11:13 AEDT # Added MacOS SMB guest sharing check # 8.5.5: Wed 1 Nov 2023 19:56:46 AEDT # Updated documentation # 8.5.6: Wed 1 Nov 2023 20:43:59 AEDT # Updated kernel accounting test for MacOS Sonoma # 8.5.7: Wed 1 Nov 2023 21:10:07 AEDT # Updated firewall logging test for MacOS Sonoma # 8.5.8: Wed 1 Nov 2023 21:22:02 AEDT # Updated bonjour advertising test for MacOS Sonoma # 8.5.9: Wed 1 Nov 2023 22:10:04 AEDT # Updated web sharing and NFS check for MacOS Sonoma # 8.6.0: Thu 2 Nov 2023 07:15:56 AEDT # Updated documentation # 8.6.1: Thu 2 Nov 2023 08:35:25 AEDT # Added Apple Mobile File Integrity check # 8.6.2: Thu 2 Nov 2023 08:58:41 AEDT # Added MacOS Sealed System Volume check # 8.6.3: Thu 2 Nov 2023 09:31:41 AEDT # Added MacOS /System permissions check # 8.6.4: Thu 2 Nov 2023 09:58:55 AEDT # Updated MacOS password policy check for Sonoma # 8.6.5: Thu 2 Nov 2023 14:06:09 AEDT # Added APFS encrypted volume checks # 8.6.6: Thu 2 Nov 2023 14:16:30 AEDT # Added Core Storage encrypted volume checks # 8.6.7: Thu 2 Nov 2023 14:55:46 AEDT # Updated sudoers timeout check # 8.6.8: Thu 2 Nov 2023 15:19:35 AEDT # Added sudoers timestamp check # 8.6.9: Thu 2 Nov 2023 15:39:28 AEDT # Updated documentation # 8.7.0: Thu 2 Nov 2023 15:48:28 AEDT # Updated documentation # 8.7.1: Thu 2 Nov 2023 20:11:40 AEDT # Added Safari history limit check # 8.7.2: Thu 2 Nov 2023 20:23:00 AEDT # Added Safari Fradulent Website Warning check # 8.7.3: Thu 2 Nov 2023 21:12:05 AEDT # Added Safari Tracking check # 8.7.4: Thu 2 Nov 2023 21:19:57 AEDT # Added Hide IP Address in Safari check # 8.7.5: Thu 2 Nov 2023 21:47:18 AEDT # Added Safari Advertising Privacy Protection check # 8.7.6: Fri 3 Nov 2023 08:07:58 AEDT # Added Safari show full URL check # 8.7.7: Fri 3 Nov 2023 09:22:30 AEDT # Added Safari auto fill check # 8.7.8: Fri 3 Nov 2023 09:50:02 AEDT # Added Safari allow popups check # 8.7.9: Fri 3 Nov 2023 10:09:51 AEDT # Added Safari Javascript check # 8.8.0: Fri 3 Nov 2023 10:14:10 AEDT # Added Safari status bar check # 8.8.1: Fri 3 Nov 2023 11:45:26 AEDT # Added MacOS Administrative login to another session check # 8.8.2: Fri 3 Nov 2023 19:38:55 AEDT # Code cleanup for MacOS defaults function # 8.8.3: Fri 3 Nov 2023 22:00:36 AEDT # Improved MacOS version handling # 8.8.4: Sat 4 Nov 2023 15:00:34 AEDT # Added check for gsettings when running gnome checks # 8.8.5: Sat 4 Nov 2023 16:31:08 AEDT # Improved tcpwrappers check # 8.8.6: Sat 4 Nov 2023 16:50:01 AEDT # Improved verbose output # 8.8.7: Sun 12 Nov 2023 20:41:54 AEDT # Fixed PAM based account lockout issue # 8.8.8: Sun 12 Nov 2023 20:57:03 AEDT # More fixes for PAM checks # 8.8.9: Sun 9 Jun 2024 15:02:54 AEST # Fixed check_file_perms.sh find depth # 8.9.0: Fri Jun 14 04:51:06 PM AEST 2024 # Fixed PAE check # 8.9.1: Mon Jun 17 02:11:39 PM AEST 2024 # Improved wireless test # 8.9.2: Mon Jun 17 02:19:52 PM AEST 2024 # Updated motd secure message check # 8.9.3: Mon Jun 17 02:39:20 PM AEST 2024 # Updated ssh config check # 8.9.4: Mon Jun 17 04:26:30 PM AEST 2024 # Fixes for auditd checks # 8.9.5: Mon Jun 17 04:52:05 PM AEST 2024 # Improved syslog check # 8.9.6: Tue Jun 18 18:23:09 AEST 2024 # Fixed code to print module info # 8.9.7: Tue Jun 18 18:52:41 AEST 2024 # Updated command line handling # 8.9.8: Tue 18 Jun 2024 21:30:13 AEST # Updated defaults # 8.9.9: Tue Jun 18 11:41:53 PM AEST 2024 # Improved systemctl check # 9.0.0: Wed Jun 19 04:35:29 PM AEST 2024 # Improvements to reporting output # 9.0.1: Wed Jun 19 08:24:22 PM AEST 2024 # Improvements to reporting output # 9.0.2: Wed Jun 19 09:30:20 PM AEST 2024 # Improvements to reporting output # 9.0.3: Fri 28 Jun 2024 14:28:00 AEST # Major cleanup of code underway # 9.0.4: Fri Jun 28 03:49:10 PM AEST 2024 # Fixed bug with old users check # 9.0.5 Fri Jun 28 04:37:05 PM AEST 2024 # Fixed bug with daemon unmask check # 9.0.6: Fri Jun 28 04:46:27 PM AEST 2024 # Improved select function check # 9.0.7: Fri 28 Jun 2024 17:09:33 AEST # Bug fixes # 9.0.8: Fri Jul 5 10:27:59 AM AEST 2024 # Formatting and bug fixes # 9.0.9: Fri Jul 5 01:41:18 PM AEST 2024 # Improved avahi conf check # 9.1.0: Fri Jul 5 03:57:46 PM AEST 2024 # Output format improvements # 9.1.1: Fri Jul 5 04:03:52 PM AEST 2024 # Fixed bug with systemctl command # 9.1.2: Fri Jul 5 07:36:42 PM AEST 2024 # Added directory check to file check # 9.1.3: Fri Jul 5 08:59:48 PM AEST 2024 # Added directory check to file append # 9.1.4: Sat Jul 6 09:48:27 AM AEST 2024 # Initial clean up of defaults # 9.1.5: Sat Jul 6 11:09:59 AM AEST 2024 # Updated documentation # 9.1.6: Sat Jul 6 11:18:47 AM AEST 2024 # Cleaned up some commands # 9.1.7: Sat Jul 6 11:47:47 AM AEST 2024 # Fixed temp_file assignment # 9.1.8: Sat Jul 6 14:10:53 AEST 2024 # Disable results output when running in restore mode # 9.1.9: Sat Jul 6 14:56:17 AEST 2024 # Added file checks for deleting some files # 9.2.0: Sat Jul 6 15:07:51 AEST 2024 # Bug fixes # 9.2.1: Sat Jul 6 08:35:44 PM AEST 2024 # Fixed wheel group test # 9.2.2: Sat Jul 6 21:04:48 AEST 2024 # Fixed find command in cron test # 9.2.3: Sat Jul 6 21:11:40 AEST 2024 # Improved gnome automount test # 9.2.4: Sat Jul 6 21:20:59 AEST 2024 # Improved gnome screen lock test # 9.2.5: Sat Jul 6 21:27:38 AEST 2024 # Improved cron allow test # 9.2.6: Sat Jul 6 21:57:14 AEST 2024 # Improved gsettings function # 9.2.7: Sun Jul 7 10:07:11 AM AEST 2024 # Improved file backup function # 9.2.8: Sun Jul 7 10:12:53 AM AEST 2024 # Made file warnings consistent when file doesn't exist # 9.2.9: Mon Jul 8 12:32:14 AEST 2024 # Improved aide check # 9.3.0: Mon Jul 8 13:54:59 AEST 2024 # Improved tcp_wrappers check # 9.3.1: Tue 9 Jul 2024 12:19:45 AEST # Initial clean up of options to allow other containers besides docker # 9.3.2: Tue Jul 9 14:47:38 AEST 2024 # Bug fixes # 9.3.3: Tue Jul 9 21:23:27 AEST 2024 # Cleaned up tests/list options, added some multipass support for testing and updated documentation # 9.3.4: Wed Jul 10 03:07:15 PM AEST 2024 # Improved dialog # 9.3.5: Wed Jul 10 03:12:22 PM AEST 2024 # Bug fixes # 9.3.6: Wed Jul 10 10:15:15 PM AEST 2024 # Bug fixes and improvements # 9.3.7: Thu Jul 11 02:05:40 PM AEST 2024 # Added strict and debug switches # 9.3.8: Thu Jul 11 05:07:08 PM AEST 2024 # Fixed return code in check_systemctl_service # 9.3.9: Fri Jul 12 10:48:58 AM AEST 2024 # Bug fixes and improvements # 9.4.0: Fri Jul 12 01:26:48 PM AEST 2024 # Bug fixes # 9.4.1: Fri Jul 12 05:06:40 PM AEST 2024 # Bug fixes # 9.4.2: Fri Jul 12 08:43:30 PM AEST 2024 # Fixed iptables check # 9.4.3: Fri Jul 12 08:50:57 PM AEST 2024 # Fixed apparmor check # 9.4.4: Fri Jul 12 09:00:09 PM AEST 2024 # Fixed sendmail daemon check # 9.4.5: Fri Jul 12 09:09:28 PM AEST 2024 # Fixed ssh root key check # 9.4.6: Fri Jul 12 09:43:08 PM AEST 2024 # Fixed duplicate users check # 9.4.7: Sat Jul 13 09:09:54 AM AEST 2024 # Fixed user dot files check # 9.4.8: Sat Jul 13 09:14:14 AM AEST 2024 # Fixed password fields check # 9.4.9: Sat Jul 13 09:18:36 AM AEST 2024 # Fixed reserved ID check # 9.5.0: Sat Jul 13 09:35:18 AM AEST 2024 # Fixed daemon umask check # 9.5.1: Sat Jul 13 10:09:32 AM AEST 2024 # Fixed wheel group check # 9.5.2: Sat Jul 13 10:14:43 AM AEST 2024 # Added wheel group and password hashing switches # 9.5.3: Sat Jul 13 10:30:34 AM AEST 2024 # Fixed file permissions check # 9.5.4: Sat Jul 13 10:38:11 AM AEST 2024 # Fixed old users check # 9.5.5: Sat Jul 13 11:24:41 AM AEST 2024 # Fixed cron check and added anacron switch # 9.5.6: Sat Jul 13 11:32:17 AM AEST 2024 # Fixed shadow group check # 9.5.7: Sat Jul 13 11:39:27 AM AEST 2024 # Fixed xlogin check # 9.5.8: Sat Jul 13 11:46:38 AM AEST 2024 # Fixed gnome banner check # 9.5.9: Sat Jul 13 11:57:17 AM AEST 2024 # Fixed krb5 check # 9.6.0: Sat Jul 13 12:03:35 PM AEST 2024 # Fixed NIS entries check # 9.6.1: Sat Jul 13 12:13:35 PM AEST 2024 # Fixed avahi daemon check # 9.6.2: Sat Jul 13 12:16:42 PM AEST 2024 # Fixed mount setuid check # 9.6.3: Sat Jul 13 12:26:27 PM AEST 2024 # Fixed NFS check # 9.6.4: Sat Jul 13 12:31:12 PM AEST 2024 # Fixed filesystem mount check # 9.6.5: Sat Jul 13 12:48:49 PM AEST 2024 # Fixed syslog server check # 9.6.6: Sat Jul 13 12:54:24 PM AEST 2024 # Fixed SNMP test # 9.6.7: Sat Jul 13 01:03:46 PM AEST 2024 # Fixed chrony check # 9.6.8: Sat Jul 13 01:07:45 PM AEST 2024 # Fixed dhcp server test # 9.6.9: Sat Jul 13 01:10:26 PM AEST 2024 # Fixed apport check # 9.7.0: Sat Jul 13 01:15:04 PM AEST 2024 # Fixed SPARC hardware check # 9.7.1: Sat Jul 13 01:27:35 PM AEST 2024 # Documentation updates # 9.7.2: Sat 13 Jul 2024 17:33:22 AEST # Fixed version detection on MacOS # 9.7.3: Sat 13 Jul 2024 17:37:35 AEST # Fixed dmidecode check # 9.7.4: Sat 13 Jul 2024 17:41:13 AEST # Fixed SSH sandbox check # 9.7.5: Sat 13 Jul 2024 17:43:01 AEST # Fixed password strength test # 9.7.6: Sat 13 Jul 2024 17:48:24 AES # Fixed kernel accounting check # 9.7.7: Sat 13 Jul 2024 17:57:16 AEST # Fixed ntp check # 9.7.8: Sat 13 Jul 2024 20:04:00 AEST # Fixes for MacOS # 9.7.9: Sat 13 Jul 2024 20:41:18 AEST # More fixes for MacOS # 9.8.0: Sat 13 Jul 2024 22:01:16 AEST # Fixes for MacOS defaults checks # 9.8.1: Sat 13 Jul 2024 22:05:46 AEST # Fixed file sharing check # 9.8.2: Sat 13 Jul 2024 22:10:29 AEST # Fixed firewall setting check # 9.8.3: Sat 13 Jul 2024 22:14:57 AEST # More firewall setting check fixes # 9.8.4: Sat 13 Jul 2024 22:24:09 AEST # Fixed pmset check # 9.8.5: Sat 13 Jul 2024 22:37:04 AEST # Improved MacOS defaults check # 9.8.6: Sat 13 Jul 2024 22:42:24 AEST # Fixed dscl check # 9.8.7: Sat 13 Jul 2024 22:50:22 AEST # Fixed remote management check # 9.8.8: Sat 13 Jul 2024 22:56:50 AEST # Fixed safe downloads check # 9.8.9: Sat 13 Jul 2024 23:06:29 AEST # Fixed keychain lock check # 9.9.0: Sat 13 Jul 2024 23:09:40 AEST # Fixed application permissions check # 9.9.1: Sat 13 Jul 2024 23:12:47 AEST # Fixed touch ID check # 9.9.2: Sat 13 Jul 2024 23:15:06 AEST # Fixed APFS check # 9.9.3: Sat 13 Jul 2024 23:17:18 AEST # Fixed safari history check # 9.9.4: Sat 13 Jul 2024 23:20:30 AEST # Fixed safari warning check # 9.9.5: Sat 13 Jul 2024 23:23:49 AEST # Updated documentation # 9.9.6: Sun 14 Jul 2024 10:45:51 AEST # Fixed multipass VM check # 9.9.7: Sun 14 Jul 2024 11:28:05 AEST # Added debug switch to multipass # 9.9.8: Sun 14 Jul 2024 11:39:07 AEST # Added select switch to select # 9.9.9: Sun 14 Jul 2024 12:03:00 AEST # Improved systemctl check # 10.0.0: Sun 14 Jul 2024 12:08:51 AEST # Removed may need to be run as root warning for help and version switches # 10.0.1: Sun 14 Jul 2024 12:21:36 AEST # Improved gsettings check # 10.0.2: Sun Jul 14 12:36:32 AEST 2024 # More improvements to gsettings check # 10.0.3: Sun 14 Jul 2024 12:56:07 AEST # Removed check_rpm function # 10.0.4: Sun 14 Jul 2024 13:03:58 AEST # Improved select function/module handling # 10.0.5: Mon 15 Jul 2024 11:31:58 AEST # Updated output # 10.0.6: Mon Jul 22 14:59:00 AEST 2024 # Bug fixes # 10.0.7: Mon Jul 22 15:06:52 AEST 2024 # Fix for systemctl check # 10.0.8: Mon Jul 22 15:43:40 AEST 2024 # Fix for old users check # 10.0.9: Fri 25 Apr 2025 13:55:04 AEST # Code cleanup # 10.1.0: Fri 25 Apr 2025 15:49:37 AEST # Updated help routine # 10.1.1: Sat 26 Apr 2025 10:54:56 AEST # More code cleanup # 10.1.2: Sat 26 Apr 2025 11:08:06 AEST # Updated switch processing # 10.1.3: Sat 26 Apr 2025 22:35:08 AEST # Fixes recommended by Shellcheck # 10.1.4: Sun 27 Apr 2025 11:35:45 AEST # Fixed keychain sync check # 10.1.5: Sun 27 Apr 2025 17:17:40 AEST # Documentation updates # 10.1.6: Sun 27 Apr 2025 18:53:29 AEST # Updated modprobe filesystem kernel modules check # 10.1.7: Sun Apr 27 07:58:25 PM AEST 2025 # Updated filesystem checks # 10.1.8: Sun 27 Apr 2025 21:25:56 AEST # Updated AppArmor test # 10.1.9: Sun 27 Apr 2025 22:41:11 AEST # Updated documentation # 10.2.0: Sun 27 Apr 2025 23:10:52 AEST # Updated virtual memory test and added ptrace test # 10.2.1: Sun 27 Apr 2025 23:45:37 AEST # Updated documentation and gdm test # 10.2.2: Mon Apr 28 21:04:35 AEST 2025 # Broke out functions from main script # 10.2.3: Tue Apr 29 09:28:23 AEST 2025 # Updated audit tests and documentation # 10.2.4: Tue Apr 29 10:00:28 AEST 2025 # Updated rsyslog log rotate test # 10.2.5: Tue Apr 29 13:07:05 AEST 2025 # Updated journald test # 10.2.6: Tue Apr 29 13:27:54 AEST 2025 # Added shell timeout check # 10.2.7: Tue Apr 29 15:16:39 AEST 2025 # Updated shell check # 10.2.8: Tue Apr 29 15:20:43 AEST 2025 # Updated documentation # 10.2.9: Tue Apr 29 18:19:12 AEST 2025 # Added root access test # 10.3.0: Tue Apr 29 20:18:09 AEST 2025 # Added non root UID 0 test # 10.3.1: Tue Apr 29 20:50:36 AEST 2025 # Added non root GID 0 test # 10.3.2: Tue Apr 29 21:17:01 AEST 2025 # Added password history test # 10.3.3: Tue Apr 29 22:10:06 AEST 2025 # Added inactive password lock test # 10.3.4: Tue Apr 29 22:17:53 AEST 2025 # Updated documentation # 10.3.5: Wed Apr 30 12:03:09 AEST 2025 # Started adding addition pam checks # 10.3.6: Wed 30 Apr 2025 21:52:52 AEST # Cleaned up PAM tests and added authtok test # 10.3.7: Thu 1 May 2025 09:48:32 AEST # Updated documentation and password quality tests # 10.3.8: Thu 1 May 2025 11:19:34 AEST # Updated tests and documentation # 10.3.9: Thu 1 May 2025 12:00:56 AEST # Renamed chkconfig test to make it more generic and updated documentation # 10.4.0: Thu 1 May 2025 12:06:10 AEST # Updated java test # 10.4.1: Thu 1 May 2025 13:35:33 AEST # Updated tests and documentation and add ftp client package test # 10.4.2: Thu 1 May 2025 14:22:20 AEST # Updated tests and documentation # 10.4.3: Thu 1 May 2025 17:17:11 AEST # Updated tests and documentation # 10.4.4: Thu 1 May 2025 21:09:59 AEST # Updated password quality documentation and tests # 10.4.5: Thu 1 May 2025 22:20:53 AEST # Documentation and test updates # 10.4.6: Fri 2 May 2025 09:03:49 AEST # Added sudo authenticate test # 10.4.7: Fri 2 May 2025 09:22:59 AEST # Added sudo NOPASSWD test # 10.4.8: Fri 2 May 2025 10:42:57 AEST # Updated sudo tests # 10.4.9: Fri 2 May 2025 15:34:21 AEST # Updated SSH config tests # 10.5.0: Fri 2 May 2025 16:23:34 AEST # Added SSH permissions test # 10.5.1: Fri 2 May 2025 21:30:47 AEST # Formatting cleanup # 10.5.2: Sat 3 May 2025 15:57:37 AEST # More formatting cleanup # 10.5.3: Sat 3 May 2025 16:33:59 AEST # Moved shellcheck function to core # 10.5.4: Sat 3 May 2025 17:09:16 AEST # Shellcheck fixes # 10.5.5: Sun 4 May 2025 16:54:11 AEST # Added ansible output for some tests # 10.5.6: Mon 5 May 2025 10:37:12 AEST # Added file comment function and updated ansible in some tests # 10.5.7: Wed 7 May 2025 15:07:01 AEST # Updated touch ID test # 10.5.8: Wed 7 May 2025 15:41:38 AEST # Updated Solaris audit class check # 10.5.9: Thu 8 May 2025 10:50:22 AEST # Updated some ansible stanzas # 10.6.0: Fri 9 May 2025 15:49:24 AEST # Updated AppArmor test # 10.6.1: Fri 9 May 2025 15:51:10 AEST # Fixed dot files test # 10.6.2: Mon 12 May 2025 10:57:47 AEST # Updated lockdown and restore commands in functions # 10.6.3: Mon 12 May 2025 14:03:15 AEST # Updated lockdown and restore commands in some modules # 10.6.4: Mon 12 May 2025 14:30:16 AEST # Updated lockdown and restore commands in some modules # 10.6.5: Mon 12 May 2025 15:58:48 AEST # Updated lockdown and restore commands in some modules # 10.6.6: Thu 15 May 2025 18:10:29 AEST # Added sudo check to some tests # 10.6.7: Thu 15 May 2025 19:02:52 AEST # Cleaned up some variable names # 10.6.8: Thu 15 May 2025 20:42:06 AEST # Updated xlogin test and some other tests # 10.6.9: Thu 15 May 2025 22:23:07 AEST # Updated formating of some tests # 10.7.0: Sun 18 May 2025 15:52:53 AEST # Updated formating of some tests # 10.7.1: Mon May 19 00:26:10 AEST 2025 # Added function to print module and function names # 10.7.2: Mon May 19 00:30:40 AEST 2025 # Fixed typos # 10.7.3: Thu 29 May 2025 11:55:24 AEST # Improved print_audit_info routine # 10.7.4: Thu 29 May 2025 14:50:10 AEST # Added lockdown check # 10.7.5: Thu 29 May 2025 15:38:42 AEST # Added dryrun switch # 10.7.6: Thu 29 May 2025 15:47:11 AEST # Fixed lockdown check # 10.7.7: Thu 29 May 2025 16:32:48 AEST # Improved listing of backups # 10.7.8: Thu 29 May 2025 17:12:25 AEST # Added lockdown/restore counting # 10.7.9: Thu 29 May 2025 20:05:20 AEST # Output improvements # 10.8.0: Fri 30 May 2025 13:21:01 AEST # Sudo improvements # 10.8.1: Fri 30 May 2025 14:24:37 AEST # Improved restore function # 10.8.2: Fri 30 May 2025 14:30:04 AEST # More improvements # 10.8.3: Fri 30 May 2025 17:32:12 AEST # Improved report # 10.8.4: Fri 30 May 2025 19:42:47 AEST # Cleaned up some variable names # 10.8.5: Sat 31 May 2025 14:21:00 AEST # Fixed check_file_value routine logging # 10.8.6: Sat 31 May 2025 14:29:11 AEST # Stopped check_environment running multiple times # 10.8.7: Sat 31 May 2025 15:30:36 AEST # Improved check_file_value routine # 10.8.8: Sat May 31 15:38:14 AEST 2025 # Fixed bug with module_name being recast # 10.8.9: Sat 31 May 2025 16:03:06 AEST # Fixes based on POSIX sh recommendations from shellcheck # 10.9.0: Sat 31 May 2025 16:09:06 AEST # More shellcheck recommendations # 10.9.1: Sat 31 May 2025 17:25:53 AEST # Updated documentation # 10.9.2: Thu Jan 15 11:57:32 AEDT 2026 # Updated Ubuntu codenames # 10.9.3: Thu Jan 15 12:38:51 AEDT 2026 # Fixed OS version check in aide check # 10.9.4: Thu Jan 15 14:16:46 AEDT 2026 # Improved virtual check # 10.9.5: Thu Jan 15 14:22:12 AEDT 2026 # Added output file and format options for future improvements # 10.9.6: Thu Jan 15 15:25:37 AEDT 2026 # Added hostname and domainname to OS info # 10.9.7: Thu Jan 15 21:17:22 AEDT 2026 # Added initial CSV output # 10.9.8: Thu Jan 15 21:26:27 AEDT 2026 # Fixed typo # 10.9.9: Mon Jan 19 11:51:25 AEDT 2026 # Added initial Azure stub # 11.0.0: Wed Jan 21 11:51:25 AEDT 2026 # Added Azure Storage Accounts audit stub # 11.0.1: Wed Jan 21 15:52:58 AEDT 2026 # Added Azure Storage Accounts Key Expiration check # 11.0.2: Thu Jan 22 14:47:19 AEDT 2026 # Fixed Azure Storage Accounts Key Expiration check # 11.0.3: Thu Jan 22 17:10:30 AEDT 2026 # Added Azure Storage Accounts Key Regeneration check # 11.0.4: Thu 22 Jan 2026 18:37:22 AEDT # Added command_message routine # 11.0.5: Thu 22 Jan 2026 20:44:42 AEDT # Added Private Endpoint check for Storage Accounts # 11.0.6: Thu 22 Jan 2026 21:29:00 AEDT # Added Public Network Access check for Storage Accounts # 11.0.7: Thu 22 Jan 2026 21:36:22 AEDT # Added fix commands for some Storage Accounts tests # 11.0.8: Thu 22 Jan 2026 21:41:33 AED # Added check to verify default network access rule for Storage Accounts # 11.0.9: Thu 22 Jan 2026 21:46:22 AEDT # Added generic check_azure_storage_account_value function # 11.1.0: Thu 22 Jan 2026 21:50:22 AEDT # Added check to verify Microsoft Entra authorization for Storage Accounts # 11.1.1: Thu 22 Jan 2026 21:51:33 AEDT # Improved check_azure_storage_account_value function # 11.1.2: Thu 22 Jan 2026 21:56:22 AEDT # Added check to verify Azure services on the trusted services list for Storage Accounts # 11.1.3: Thu 22 Jan 2026 22:06:22 AEDT # Added check to verify Secure transfer required for Storage Accounts # 11.1.4: Thu 22 Jan 2026 22:11:22 AEDT # Added check to verify Cross Tenant Replication for Storage Accounts # 11.1.5: Thu 22 Jan 2026 22:16:22 AEDT # Added check to verify Allow blob public access for Storage Accounts # 11.1.6: Thu 22 Jan 2026 22:21:22 AEDT # Added Minimum TLS version check for Storage Accounts # 11.1.7: Fri 23 Jan 2026 10:37:22 AEDT # Added check_azure_resource_manager_locks function # 11.1.8: Fri 23 Jan 2026 10:42:22 AEDT # Added Azure Resource Manager Delete locks check for Storage Accounts # 11.1.9: Fri 23 Jan 2026 10:46:22 AEDT # Added Azure Resource Manager ReadOnly locks check for Storage Accounts # 11.2.0: Fri 23 Jan 2026 11:12:39 AEDT # Added Azure Storage Accounts Redundancy check # 11.2.1: Fri 23 Jan 2026 11:51:22 AEDT # Bug fixes and improvements # 11.2.2: Fri 23 Jan 2026 12:06:22 AEDT # Added check_azure_storage_blob_value function # 11.2.3: Fri 23 Jan 2026 12:11:22 AEDT # Added check for Azure Storage Blob Soft Delete # 11.2.4: Fri 23 Jan 2026 12:16:22 AEDT # Added check for Azure Storage Blob Days Retained # 11.2.5: Fri 23 Jan 2026 14:12:30 AEDT # Added Azure auth mode # 11.2.6: Fri 23 Jan 2026 15:00:19 AEDT # Added check_azure_storage_container_value function # 11.2.7: Fri 23 Jan 2026 15:02:22 AEDT # Added check for Azure Storage Container Soft Delete # 11.2.8: Fri 23 Jan 2026 15:04:22 AEDT # Added check for Azure Storage Container Days Retained # 11.2.9: Fri 23 Jan 2026 15:06:22 AEDT # Added check for Azure Storage Container Versioning # 11.3.1: Fri 23 Jan 2026 20:06:22 AEDT # Added check of Azure File Shares # 11.3.2: Fri 23 Jan 2026 20:06:22 AEDT # Added check for Azure File Shares Soft Delete # 11.3.3: Fri 23 Jan 2026 20:06:22 AEDT # Added check for Azure File Shares Days Retained # 11.3.4: Fri 23 Jan 2026 20:06:22 AEDT # Added check for Azure File Shares SMB Protocol Version # 11.3.5: Fri 23 Jan 2026 20:06:22 AEDT # Added check for Azure File Shares SMB Channel Encryption # 11.3.6: Fri 23 Jan 2026 20:51:27 AEDT # Added Azure CLI extension checks # 11.3.7: Sat 24 Jan 2026 14:19:25 AEDT # Added Azure Databricks check routine # 11.3.8: Sat 24 Jan 2026 14:22:22 AEDT # Added Azure Monitor check routine # 11.3.9: Sat 24 Jan 2026 17:16:34 AEDT # Added Azure Databricks TBD check list # 11.4.0: Sat 24 Jan 2026 17:18:34 AEDT # Added Azure Databricks No Public IP check # 11.4.1: Sat 24 Jan 2026 17:19:34 AEDT # Added Azure Databricks Private Link check # 11.4.2: Sat 24 Jan 2026 17:20:34 AEDT # Added Azure Databricks Private Endpoints check # 11.4.3: Sat 24 Jan 2026 17:47:34 AEDT # Added Azure Compute Services check stub # 11.4.4: Sat 24 Jan 2026 17:48:34 AEDT # Added Azure Database Services check stub # 11.4.5: Sat 24 Jan 2026 17:58:34 AEDT # Added Azure Identity Services check stub # 11.4.6: Sat 24 Jan 2026 18:07:34 AEDT # Added Azure Logging and Monitoring check stub # 11.4.7: Sat 24 Jan 2026 18:13:34 AEDT # Added Azure Networking Services check stub # 11.4.8: Sat 24 Jan 2026 18:18:34 AEDT # Added Azure Security Services check stub # 11.4.9: Sat 24 Jan 2026 18:23:34 AEDT # Added Azure Storage Services check stub # 11.5.0: Sat 24 Jan 2026 21:32:22 AEDT # Added Azure Guest Users check # 11.5.1: Sun 25 Jan 2026 10:01:40 AEDT # Added Azure User Access Administrator Role check # 11.5.2: Sun 25 Jan 2026 11:19:03 AEDT # Added Azure Custom Subscription Admin Roles check # 11.5.3: Sun 25 Jan 2026 14:54:42 AEDT # Added Azure Subscription Owners check # 11.5.4: Sun 25 Jan 2026 17:50:12 AEDT # Added Azure Subscription Diagnostic Settings check # 11.5.5: Sun 25 Jan 2026 18:01:22 AEDT # Added check to ensure Diagnostic Setting captures appropriate categories # 11.5.6: Sun 25 Jan 2026 19:40:16 AEDT # Added check to ensure Diagnostic Logs are encrypted # 11.5.7: Sun 25 Jan 2026 21:02:32 AEDT # Added Azure Survey check # 11.5.8: Mon 26 Jan 2026 12:16:32 AEDT # Split out Azure Diagnostic Settings checks into multiple routines # 11.5.9: Mon 26 Jan 2026 18:11:56 AEDT # Added Azure Key Vault Logging check # 11.6.0: Mon 26 Jan 2026 18:21:09 AEDT # Added stub for Azure NSG Flow Logs check # 11.6.1: Mon 26 Jan 2026 18:26:22 AEDT # Added stub for Azure AppService HTTP logs check # 11.6.2: Mon 26 Jan 2026 18:27:22 AEDT # Documentation and formatting updates # 11.6.3: Mon 26 Jan 2026 18:57:48 AEDT # Added stub for Azure Virtual Network Flow Logs check # 11.6.4: Mon 26 Jan 2026 21:02:22 AEDT # Added stub for Azure Entra Diagnostic Settings check # 11.6.5: Mon 26 Jan 2026 21:11:22 AEDT # Added stub for Azure Graph Diagnostic Settings check # 11.6.6: Mon 26 Jan 2026 21:15:22 AEDT # Added stub for Azure Intune Logs check # 11.6.7: Mon 26 Jan 2026 21:34:22 AEDT # Added Azure Activity Log Alerts Create Policy Assignment check # 11.6.8: Mon 26 Jan 2026 21:41:22 AEDT # Added Azure Activity Log Alerts Delete Policy Assignment check # 11.6.9: Mon 26 Jan 2026 21:46:22 AEDT # Added Azure Activity Log Alerts Create or Update Network Security Group check # 11.7.0: Tue 27 Jan 2026 08:38:22 AEDT # Added Azure Activity Log Alerts Delete Network Security Group check # 11.7.1: Tue 27 Jan 2026 08:51:22 AEDT # Added Azure Activity Log Alerts Create or Update Security Solution check # 11.7.2: Tue 27 Jan 2026 08:54:22 AEDT # Added Azure Activity Log Alerts Delete Security Solution check # 11.7.3: Tue 27 Jan 2026 08:57:22 AEDT # Added Azure Activity Log Alerts Create or Update SQL Server Firewall Rule check # 11.7.4: Tue 27 Jan 2026 09:00:22 AEDT # Added Azure Activity Log Alerts Delete SQL Server Firewall Rule check # 11.7.5: Tue 27 Jan 2026 09:03:22 AEDT # Added Azure Activity Log Alerts Create or Update Public IP Address rule check # 11.7.6: Tue 27 Jan 2026 09:06:22 AEDT # Added Azure Activity Log Alerts Delete Public IP Address rule check # 11.7.7: Tue 27 Jan 2026 09:09:22 AEDT # Added Azure Activity Log Alerts Service Health check # 11.7.8: Tue 27 Jan 2026 09:26:22 AEDT # Added Azure Application Insights check # 11.7.9: Tue 27 Jan 2026 09:38:22 AEDT # Added Azure Resource Logging check # 11.8.0: Tue 27 Jan 2026 10:08:22 AEDT # Added Azure SKU Basic/Consumption check # 11.8.1: Tue 27 Jan 2026 11:16:00 AEDT # Updated documentation # 11.8.2: Tue 27 Jan 2026 12:18:37 AEDT # Added Azure Extensions check # 11.8.3: Tue 27 Jan 2026 13:22:22 AEDT # Updated documentation # 11.8.4: Tue 27 Jan 2026 14:10:22 AEDT # Added Azure Microsoft Defender check for CSPM # 11.8.5: Tue 27 Jan 2026 14:40:22 AEDT # Added Azure Microsoft Defender check for CWP # 11.8.6: Tue 27 Jan 2026 15:14:52 AEDT # Added status check to Microsoft Defender check # 11.8.7: Tue 27 Jan 2026 15:24:22 AEDT # Added Azure Microsoft Defender check for Defender for Servers # 11.8.8: Tue 27 Jan 2026 15:38:22 AEDT # Added function to check Azure security setting values # 11.8.9: Tue 27 Jan 2026 15:42:22 AEDT # Code cleanup # 11.9.0: Tue 27 Jan 2026 15:44:22 AEDT # Typo fixes # 11.9.1: Tue 27 Jan 2026 19:21:22 AEDT # Added error handling to systemctl commands # 11.9.2: Tue 27 Jan 2026 19:46:22 AEDT # Added check that enpoint protection is enabled # 11.9.3: Tue 27 Jan 2026 19:51:22 AEDT # Added check that agentless scanning is enabled # 11.9.4: Tue 27 Jan 2026 20:16:55 AEDT # Added check for Microsoft Defender for Containers # 11.9.5: Tue 27 Jan 2026 20:19:55 AEDT # Added check for Microsoft Defender for Storage # 11.9.6: Tue 27 Jan 2026 20:23:55 AEDT # Added check for Microsoft Defender for App Services # 11.9.7: Tue 27 Jan 2026 20:26:55 AEDT # Added check for Microsoft Defender for Azure Cosmos DB # 11.9.8: Tue 27 Jan 2026 20:31:22 AEDT # Added check for Microsoft Defender for Open-Source RDBMS # 11.9.9: Tue 27 Jan 2026 20:34:22 AEDT # Updated documentation # 12.0.0: Tue Jan 27 20:36:59 AEDT 2026 # Added check for Microsoft Defender for SQL Server # 12.0.1: Tue Jan 27 20:39:35 AEDT 2026 # Added check for Microsoft Defender for SQL Servers on Machines # 12.0.2: Tue Jan 27 20:43:22 AEDT 2026 # Added check for Microsoft Defender for Azure Key Vault # 12.0.3: Tue Wed 28 10:16:12 AEDT 2026 # Added check for Microsoft Defender for Resource Manager # 12.0.4: Tue Wed 28 12:58:38 AEDT 2026 # Added Azure Security Contact check # 12.0.5: Tue Wed 28 13:26:02 AEDT 2026 # Added Azure Security Contact check for email address # 12.0.6: Tue Wed 28 13:28:02 AEDT 2026 # Added Azure Security Contact check for alert notifications # 12.0.7: Tue Wed 28 13:30:02 AEDT 2026 # Updated documentation # 12.0.8: Tue Wed 28 13:35:02 AEDT 2026 # Added Azure Security Contact check for alert notifications severity # 12.0.9: Tue Wed 28 17:08:33 AEDT 2026 # Improved Microsoft Defender check # 12.1.0: Thu 29 Jan 2026 15:07:22 AEDT # Added Azure Key Vault check for key enabled status # 12.1.1: Thu 29 Jan 2026 15:10:22 AEDT # Added Azure Key Vault check for key expiry date # 12.1.2: Thu 29 Jan 2026 15:46:51 AEDT # Updated output for checks to be more consistent # 12.1.3: Thu 29 Jan 2026 15:53:49 AEDT # Updated checks for Azure Key Vault keys # 12.1.4: Thu 29 Jan 2026 17:32:22 AEDT # Added Azure Key Vault Purge Protection check # 12.1.5: Thu 29 Jan 2026 18:04:54 AEDT # Added Azure Key Vault RBAC check # 12.1.6: Thu 29 Jan 2026 19:58:18 AEDT # Function variable alignment for azure checks # 12.1.7: Thu 29 Jan 2026 21:01:10 AEDT # Added Azure Key Vault Public Network Access check # 12.1.8: Thu 29 Jan 2026 21:30:38 AEDT # Added Azure Key Vault Private Endpoint check # 12.1.9: Fri 30 Jan 2026 14:04:38 AEDT # Added command_message function # 12.2.0: Fri 30 Jan 2026 14:06:38 AEDT # Added key vault check for key rotation # 12.2.1: Fri 30 Jan 2026 14:47:22 AEDT # Fixed Azure Databricks check # 12.2.2: Fri 30 Jan 2026 15:50:22 AEDT # Started adding command_message function support # 12.2.3: Fri 30 Jan 2026 15:53:22 AEDT # Updated documentation # 12.2.4: Fri 30 Jan 2026 15:56:22 AEDT # Fixed Azure Application Insights check # 12.2.5: Fri 30 Jan 2026 15:58:22 AEDT # Cleaned up Azure User Access Administrator Role check # 12.2.6: Fri 30 Jan 2026 16:18:22 AEDT # Cleaned up some Azure storage checks # 12.2.7: Fri 30 Jan 2026 16:46:22 AEDT # Improved environment checking # 12.2.8: Fri 30 Jan 2026 17:04:10 AEDT # Added Azure login check # 12.2.9: Fri 30 Jan 2026 17:12:10 AEDT # Updated Azure Monitor Diagnostic Settings check # 12.3.0: Sat 31 Jan 2026 11:59:26 AEDT # Updated Azure Activity Log Alerts check # 12.3.1: Sat 31 Jan 2026 12:34:51 AEDT # Updated Azure Key Vault check # 12.3.2: Sat 31 Jan 2026 12:36:51 AEDT # Updated Azure Key Vault logging check # 12.3.3: Sat 31 Jan 2026 15:06:48 AEDT # Added command_message support to more Azure modules/functions # 12.3.4: Sat 31 Jan 2026 15:47:22 AEDT # Added command_message support to check_environment # 12.3.5: Sun 01 Feb 2026 11:01:22 AEDT # Added command_message support to modules in users directory # 12.3.6: Sun 01 Feb 2026 15:43:22 AEDT # Added command_message support to modules in wheel directory # 12.3.7: Sun 01 Feb 2026 15:45:22 AEDT # Added command_message support to modules in sudo directory # 12.3.8: Sun 01 Feb 2026 15:47:22 AEDT # Added command_message support to modules in sunos directory # 12.3.9: Sun 01 Feb 2026 15:49:22 AEDT # Added command_message support to modules in syslog directory # 12.4.0: Sun 01 Feb 2026 15:51:22 AEDT # Added command_message support to modules in talk directory # 12.4.1: Sun 01 Feb 2026 15:53:22 AEDT # Added command_message support to modules in tcp directory # 12.4.2: Sun 01 Feb 2026 15:55:22 AEDT # Added command_message support to modules in telnet directory # 12.4.3: Sun 01 Feb 2026 20:54:46 AEDT # Added command_message support to modules in ssh directory # 12.4.4: Sun 01 Feb 2026 20:56:46 AEDT # Added command_message support to modules in services directory # 12.4.5: Sun 01 Feb 2026 21:04:54 AEDT # Added command_message support to modules in remote directory # 12.4.6: Sun 01 Feb 2026 21:17:54 AEDT # Added command_message support to modules in print directory # 12.4.7: Sun 01 Feb 2026 21:19:16 AEDT # Added command_message support to modules in power directory # 12.4.8: Mon 02 Feb 2026 07:18:53 AEDT # Added command_message support to modules in password directory # 12.4.9: Mon 02 Feb 2026 07:32:53 AEDT # Added command_message support to modules in pam directory # 12.5.0: Mon 02 Feb 2026 07:51:53 AEDT # Added command_message support to modules in nis directory # 12.5.1: Mon 02 Feb 2026 08:00:22 AEDT # Added command_message support to modules in mounts directory # 12.5.2: Mon 02 Feb 2026 08:07:22 AEDT # Added command_message support to modules in mail directory # 12.5.3: Mon 02 Feb 2026 08:11:22 AEDT # Added command_message support to modules in logs directory # 12.5.4: Mon 02 Feb 2026 08:22:22 AEDT # Added command_message support to modules in login directory # 12.5.5: Mon 02 Feb 2026 08:24:22 AEDT # Added command_message support to modules in linux directory # 12.5.6: Mon 02 Feb 2026 08:26:22 AEDT # Commit some of the command_message changes # 12.5.7: Mon 02 Feb 2026 13:12:23 AEDT # Fixed typo # 12.5.8: Mon 02 Feb 2026 21:14:23 AEDT # Improved output for some checks # 12.5.9: Mon 02 Feb 2026 21:48:57 AEDT # Improved output for modules in fs directory # 12.6.0: Tue 03 Feb 2026 11:20:57 AEDT # Improved output for modules in other directories # 12.6.1: Tue 03 Feb 2026 11:23:43 AEDT # Fixed typo in audit_wireless.sh # 12.6.2: Tue 03 Feb 2026 12:24:54 AEDT # Update some more functions to use command_message # 12.6.3: Tue 03 Feb 2026 12:25:13 AEDT # Updated audit_system_accounts.sh to allow single ! in shadow field # 12.6.4: Tue 03 Feb 2026 15:32:34 AEDT # Updated more modules to use command_message # 12.6.5: Tue 03 Feb 2026 16:36:34 AEDT # Improved user account check for shells # 12.6.6: Tue 03 Feb 2026 17:18:22 AEDT # Typo fixes # 12.6.7: Tue 03 Feb 2026 20:13:17 AEDT # Updates and bug fixes # 12.6.8: Wed 04 Feb 2026 10:55:40 AEDT # Updates and bug fixes for AWS modules # 12.6.9: Wed 04 Feb 2026 11:01:40 AEDT # Added command_message support to modules in audit directory # 12.7.0: Wed 04 Feb 2026 13:19:29 AEDT # Added command_message support to modules in esxi directory # 12.7.1: Wed 04 Feb 2026 13:23:29 AEDT # Added command_message support to modules in firewall directory # 12.7.2: Wed 04 Feb 2026 13:26:29 AEDT # Added command_message support to modules in fs directory # 12.7.3: Wed 04 Feb 2026 13:28:29 AEDT # Bug fixes and improvements # 12.7.4: Thu 05 Feb 2026 20:45:10 AEDT # Added Azure NSG Security Rules check for RDP and SSH access # 12.7.5: Thu 05 Feb 2026 21:01:24 AEDT # Improved Azure NSG Security Rules check # 12.7.6: Thu 05 Feb 2026 21:10:24 AEDT # Added Azure NSG Security Rules check for UDP access # 12.7.7: Fri 06 Feb 2026 11:15:24 AEDT # Added Azure NSG Security Rules check for HTTP(S) # 12.7.8: Fri 06 Feb 2026 11:22:24 AEDT # Updated documentation for Azure NSG Security Rules check # 12.7.9: Fri 06 Feb 2026 11:26:24 AEDT # Added Azure Network Watcher check # 12.8.0: Fri 06 Feb 2026 13:32:24 AEDT # Documentation updates # 12.8.1: Fri 06 Feb 2026 13:35:24 AEDT # Added Azure Public IPs check # 12.8.2: Fri 06 Feb 2026 15:37:24 AEDT # Added Azure Network Watcher Flow Logs check # 12.8.3: Fri 06 Feb 2026 16:01:24 AEDT # Updated Azure Network Watcher Flow Logs check # 12.8.4: Fri 06 Feb 2026 16:07:24 AEDT # Added Azure Authentication Type check stub # 12.8.5: Fri 06 Feb 2026 17:29:24 AEDT # Added Azure WAF check # 12.8.6: Fri 06 Feb 2026 17:31:24 AEDT # Added Azure VNet check # 12.8.7: Sat 07 Feb 2026 11:35:30 AEDT # Added Azure WAF SSL Policy check # 12.8.8: Sat 07 Feb 2026 11:58:30 AEDT # Added Azure WAF HTTP2 check # 12.8.9: Sat 07 Feb 2026 18:40:30 AEDT # Added Azure WAF Request Body check # 12.9.0: Sun 08 Feb 2026 14:39:15 AEDT # Added Azure WAF Inspection Policy check # 12.9.1: Sun 08 Feb 2026 14:51:15 AEDT # Added Azure Network Security Perimeter module check # 12.9.2: Sun 08 Feb 2026 16:00:15 AEDT # Added Azure Network Security Perimeter check # 12.9.3: Tue 10 Feb 2026 16:00:15 AEDT # Replaced regex with case statement in several functions # 12.9.4: Tue 10 Feb 2026 16:45:15 AEDT # Added Azure Storage SAS check # 12.9.5: Tue 10 Feb 2026 16:50:15 AEDT # Added Azure Storage SAS HTTPS Only check # 12.9.6: Tue 10 Feb 2026 18:01:15 AEDT # Added Azure Storage SAS token expiration check stub # 12.9.7: Tue 10 Feb 2026 18:05:15 AEDT # Updates and improvements # 12.9.8: Thu 12 Feb 2026 13:13:41 AEDT # Updated and improvements # 12.9.9: Thu 12 Feb 2026 16:27:41 AEDT # Added Azure Elastic SAN module check # 13.0.0: Thu 12 Feb 2026 16:32:31 AEDT # Updated and improvements # 13.0.1: Thu 12 Feb 2026 16:55:41 AEDT # Added execute_command function # 13.0.2: Thu 12 Feb 2026 18:01:47 AEDT # Added Azure Elastic SAN check # 13.0.3: Fri 13 Feb 2026 11:01:47 AEDT # Added Azure Site Recovery module check # 13.0.4: Fri 13 Feb 2026 17:15:47 AEDT # Added Azure Recovery Service Vaults check # 13.0.5: Fri 13 Feb 2026 17:29:47 AEDT # Added Azure Virtual Network Access Rules check # 13.0.6: Fri 13 Feb 2026 17:51:47 AEDT # Added Azure Network Private Endpoints check # 13.0.7: Fri 13 Feb 2026 17:55:47 AEDT # Added Azure amlfs extension check # 13.0.8: Sat 14 Feb 2026 11:52:20 AEDT # Added Azure Managed Lustre check # 13.0.9: Sat 14 Feb 2026 11:55:20 AEDT # Added Azure Storage File System check # 13.1.0: Sat 14 Feb 2026 11:58:20 AEDT # Added Azure dataprotection extension check # 13.1.1: Sat 14 Feb 2026 03:50:57 PM AEDT # Added initial code for Azure Data Protection Backup Vault check # 13.1.2: Mon 16 Feb 2026 12:40:01 PM AEDT # Updates and Improvements # 13.1.3: Mon 16 Feb 2026 01:18:57 PM AEDT # Fixed check_shellcheck to use find instead of ls # 13.1.4: Mon 16 Feb 2026 01:37:57 PM AEDT # Applied shellcheck recommendation to azure functions # 13.1.5: Mon 16 Feb 2026 01:45:57 PM AEDT # Updates and improvements # 13.1.6: Mon 16 Feb 2026 02:02:57 PM AEDT # Applied shellcheck recommendations to azure modules # 13.1.7: Mon 16 Feb 2026 02:27:57 PM AEDT # Applied shellcheck recommendations to several modules # 13.1.8: Mon 16 Feb 2026 03:28:57 PM AEDT # Added Azure tenant ID support # 13.1.9: Mon 16 Feb 2026 04:52:57 PM AEDT # Added Azure allow no subscriptions support # 13.2.0: Mon 16 Feb 2026 05:01:57 PM AEDT # Added Azure Backup Vaults check # 13.2.1: Mon 16 Feb 2026 05:19:38 PM AEDT # Added additional checks to Azure Backup Vaults check # 13.2.2: Mon 16 Feb 2026 05:29:38 PM AEDT # Added additional checks to Azure Backup Vaults check # 13.2.3: Mon 16 Feb 2026 05:32:38 PM AEDT # Updates and improvements # 13.2.4: Mon 16 Feb 2026 05:45:38 PM AEDT # Added additional checks to Azure Backup Vaults check # 13.2.5: Mon 16 Feb 2026 06:38:57 PM AEDT # Added Azure Recovery Services Vault check # 13.2.6: Mon 16 Feb 2026 06:41:57 PM AEDT # Updates and improvements # 13.2.7: Tue 17 Feb 2026 10:45:57 AM AEDT # Updated Azure Recovery Services Vault check # 13.2.8: Tue 17 Feb 2026 12:54:28 PM AEDT # Added Azure File Shares check for NFS Root Squash # 13.2.9: Tue 17 Feb 2026 01:54:28 PM AEDT # Updates and improvements # 13.3.0: Tue 17 Feb 2026 02:17:28 PM AEDT # Added Azure NetApp Files check # 13.3.1: Tue 17 Feb 2026 02:27:28 PM AEDT # Updates and improvements # 13.3.2: Tue 17 Feb 2026 05:14:46 PM AEDT # Added additional Azure Elastic SAN checks # 13.3.3: Tue 17 Feb 2026 05:45:46 PM AEDT # Improved Arch Linux support # 13.3.4: Wed 18 Feb 2026 11:10:46 AM AEDT # Added Azure Databox extension check # 13.3.5: Wed 18 Feb 2026 12:06:14 PM AEDT # Added Azure Databox check # 13.3.6: Wed 18 Feb 2026 12:22:55 PM AEDT # Updates and improvements # 13.3.7: Wed 18 Feb 2026 01:59:55 PM AEDT # Updates and improvements # 13.3.8: Wed 18 Feb 2026 09:02:55 PM AEDT # Added Azure Storage Blob Policy Value check # 13.3.9: Wed 18 Feb 2026 09:05:55 PM AEDT # Updates and improvements # 13.4.0: Wed 18 Feb 2026 11:22:55 PM AEDT # Added Azure Storage Logging check for queues # 13.4.1: Wed 18 Feb 2026 11:40:55 PM AEDT # Added Azure Storage Logging check for blobs # 13.4.2: Thu 19 Feb 2026 06:45:51 AM AEDT # Added Azure Storage Logging check for tables # 13.4.3: Thu 19 Feb 2026 06:45:51 AM AEDT # Updates and improvements # 13.4.4: Thu 19 Feb 2026 12:45:51 PM AEDT # Added Azure Storage Account Delete Locks check # 13.4.5: Thu 19 Feb 2026 01:15:51 PM AEDT # Added Azure Storage Account Read-only Locks check # 13.4.6: Thu 19 Feb 2026 01:26:27 PM AEDT # Updates and improvements # 13.4.7: Fri 20 Feb 2026 06:24:27 AM AEDT # Added initial Redis Cache tests # 13.4.8: Fri 20 Feb 2026 06:24:27 AM AEDT # Updates and improvements # 13.4.9: Fri 20 Feb 2026 06:24:27 AM AEDT # Added Azure Redis Cache TLS check # 13.5.0: Fri 20 Feb 2026 06:24:27 AM AEDT # Added Azure Redis Cache Public Network Access check # 13.5.1: Fri 20 Feb 2026 09:23:27 AM AEDT # Added Azure Redis Cache Private Link check # 13.5.2: Fri 20 Feb 2026 09:58:27 AM AEDT # Added Azure redisenterprise extension check # 13.5.3: Fri 20 Feb 2026 10:01:27 AM AEDT # Added Azure Redis Enterprise function # 13.5.4: Fri 20 Feb 2026 10:23:27 AM AEDT # Added Azure Redis Enterprise Cache Customer-Managed Keys check # 13.5.5: Fri 20 Feb 2026 11:17:30 AM AEDT # Added Azure Redis Cache Access Keys Authentication check # 13.5.6: Fri 20 Feb 2026 11:22:30 AM AEDT # Added Azure Redis Cache Update Channel check # 13.5.7: Fri 20 Feb 2026 11:22:30 AM AEDT # Added Azure Cosmos DB Firewalls & Networks check # 13.5.8: Fri 20 Feb 2026 11:22:30 AM AEDT # Added Azure Cosmos DB Private Endpoints check # 13.5.9: Fri 20 Feb 2026 03:59:23 PM AEDT # Added Azure Cosmos DB Disable Local Auth check # 13.6.0: Fri 20 Feb 2026 04:09:23 PM AEDT # Updates and improvements # 13.6.1: Fri 20 Feb 2026 04:24:23 PM AEDT # Added Azure Cosmos DB Customer-Managed Keys check # 13.6.2: Fri 20 Feb 2026 06:09:23 PM AEDT # Added Azure Cosmos DB Firewalls & Networks IP Rules check # 13.6.3: Sat 21 Feb 2026 06:09:23 PM AEDT # Added Azure Cosmos DB Logging check # 13.6.4: Sat 21 Feb 2026 07:09:23 PM AEDT # Added Azure Data Factory module check # 13.6.5: Sat 21 Feb 2026 07:09:23 PM AEDT # Added Azure Data Factory Customer-Managed Keys check # 13.6.6: Sat 21 Feb 2026 07:09:23 PM AEDT # Added Azure Data Factory Managed Identities check # 13.6.7: Sat 21 Feb 2026 09:09:23 PM AEDT # Added Azure Data Factory Using Azure Key Vault check # 13.6.8: Sun 22 Feb 2026 09:39:23 PM AEDT # Added Azure Data Factory Using RBAC check # 13.6.9: Sun 22 Feb 2026 09:39:23 PM AEDT # Updates and improvements # 13.7.0: Sun 22 Feb 2026 02:19:13 PM AEDT # Added initial Azure MySQL DB module # 13.7.1: Sun 22 Feb 2026 02:19:13 PM AEDT # Added initial Azure MySQL DB function # 13.7.2: Sun 22 Feb 2026 03:19:13 PM AEDT # Added support for Azure MySQL Flexible Server # 13.7.3: Sun 22 Feb 2026 03:22:13 PM AEDT # Added support for Azure MySQL Single Server # 13.7.4: Sun 22 Feb 2026 03:22:13 PM AEDT # Added check for Azure MySQL DB Customer-Managed Keys # 13.7.5: Sun 22 Feb 2026 03:22:13 PM AEDT # Added check for Azure MySQL DB Microsoft Entra Authentication # 13.7.6: Sun 22 Feb 2026 03:22:13 PM AEDT # Updates and improvements # 13.7.7: Sun 22 Feb 2026 03:38:13 PM AEDT # Added check for Azure MySQL DB Public Network Access # 13.7.8: Sun 22 Feb 2026 03:43:13 PM AEDT # Added check for Azure MySQL DB Private Endpoints # 13.7.9: Sun 22 Feb 2026 03:50:37 PM AEDT # Added check stub for Azure MySQL DB Audit Log # 13.8.0: Sun 22 Feb 2026 03:51:37 PM AEDT # Added check stub for Azure MySQL DB Audit Log connection # 13.8.1: Sun 22 Feb 2026 03:55:37 PM AEDT # Added check stub for Azure MySQL DB Error Server Log File # 13.8.2: Sun 22 Feb 2026 03:55:37 PM AEDT # Added check stub for Azure MySQL DB Require Secure Transport # 13.8.3: Sun 22 Feb 2026 03:59:37 PM AEDT # Added check stub for Azure MySQL DB TLS Version # 13.8.4: Tue 24 Feb 2026 01:24:08 PM AEDT # Added initial Azure PostgreSQL DB module # 13.8.5: Tue 24 Feb 2026 01:34:08 PM AEDT # Added initial support for Azure PostgreSQL Flexible Server # 13.8.6: Tue 24 Feb 2026 01:44:08 PM AEDT # Added initial support for Azure PostgreSQL Single Server # 13.8.7: Tue 24 Feb 2026 01:54:08 PM AEDT # Add initial Azure PostgreSQL DB checks # 13.8.8: Tue 24 Feb 2026 02:04:08 PM AEDT # Updates and improvements # 13.8.9: Tue 24 Feb 2026 04:04:08 PM AEDT # Added initial Azure SQL DB module # 13.9.0: Tue 24 Feb 2026 04:04:08 PM AEDT # Added initial Azure SQL DB function # 13.9.1: Tue 24 Feb 2026 04:09:08 PM AEDT # Updates and improvements # 13.9.2: Tue 24 Feb 2026 21:33:43 PM AEDT # Updates and improvements # 13.9.3: Wed 25 Feb 2026 11:42:53 AM AEDT # Added initial Azure App Service App module # 13.9.4: Wed 25 Feb 2026 11:42:53 AM AEDT # Added initial Azure App Service App function # 13.9.5: Wed 25 Feb 2026 11:42:53 AM AEDT # Formating updates # 13.9.6: Wed 25 Feb 2026 11:52:53 AM AEDT # Added Azure App Service App check for Java # 13.9.7: Wed 25 Feb 2026 11:52:53 AM AEDT # Updates and improvements # 13.9.8: Wed 25 Feb 2026 12:52:53 PM AEDT # Added Azure App Service App check for Python # 13.9.9: Wed 25 Feb 2026 01:12:53 PM AEDT # Added Azure App Service App check for PHP # 14.0.0: Wed 25 Feb 2026 01:59:53 PM AEDT # Added Azure App Service App check for Basic Authentication Publishing Credentials # 14.0.1: Wed 25 Feb 2026 02:10:53 PM AEDT # Added Azure App Service App check for FTP State # 14.0.2: Wed 25 Feb 2026 03:07:53 PM AEDT # Bug fixes # 14.0.3: Wed 25 Feb 2026 03:20:53 PM AEDT # Added Azure App Service App check for HTTP Version # 14.0.4: Wed 25 Feb 2026 03:20:53 PM AEDT # Added Azure App Service App check for HTTPS Only # 14.0.5: Wed 25 Feb 2026 04:20:53 PM AEDT # Added Azure App Service App check for Minimum Inbound TLS Version # 14.0.6: Wed 25 Feb 2026 04:50:53 PM AEDT # Added Azure App Service App check for end to end TLS encryption # 14.0.7: Wed 25 Feb 2026 05:20:53 PM AEDT # Added Azure App Service App check for Remote Debugging # 14.0.8: Wed 25 Feb 2026 05:50:53 PM AEDT # Added Azure App Service App check for Client Certificates # 14.0.9: Wed 25 Feb 2026 06:20:53 PM AEDT # Added Azure App Service App check for Authentication # 14.1.0: Wed 25 Feb 2026 06:20:53 PM AEDT # Added Azure App Service App check for Managed Identities # 14.1.1: Wed 25 Feb 2026 06:20:53 PM AEDT # Added Azure App Service App check for Public Network Access # 14.1.2: Wed 25 Feb 2026 06:20:53 PM AEDT # Added Azure App Service App check for App Service Plan SKU # 14.1.3: Wed 25 Feb 2026 10:20:21 PM AEDT # Added Azure App Service App check for Private Endpoints # 14.1.4: Thu 26 Feb 2026 10:37:21 AM AEDT # Added Azure App Service App check for Private DNS Zone # 14.1.5: Thu 26 Feb 2026 10:47:21 AM AEDT # Added Azure App Service App check for Virtual Network Integration # 14.1.6: Thu 26 Feb 2026 11:00:21 AM AEDT # Added Azure App Service App check for VNet Image Pull # 14.1.7: Thu 26 Feb 2026 11:00:21 AM AEDT # Added Azure App Service App check for VNet Content Share # 14.1.8: Thu 26 Feb 2026 11:13:09 AM AEDT # Added Azure App Service App check for Cross-Origin Resource Sharing # 14.1.9: Thu 26 Feb 2026 12:42:49 PM AEDT # Added Azure App Service Deployment Slot audit module # 14.2.0: Thu 26 Feb 2026 12:44:59 AEDT # Added Azure App Service Deployment Slot function # 14.2.1: Thu 26 Feb 2026 12:47:19 AEDT # Added Azure App Service Deployment Slot Java version check # 14.2.2: Thu 26 Feb 2026 12:49:16 AEDT # Added Azure App Service Deployment Slot Python version check # 14.2.3: Thu 26 Feb 2026 12:50:09 AEDT # Added Azure App Service Deployment Slot PHP version check # 14.2.4: Thu 26 Feb 2026 13:08:16 AEDT # Added Azure App Service Deployment Slot Basic Authentication Publishing Credentials # 14.2.4: Thu 26 Feb 2026 13:10:25 AEDT # Added Azure App Service Deployment Slot FTP state check # 14.2.5: Thu 26 Feb 2026 13:11:07 AEDT # Added Azure App Service Deployment HTTP version check # 14.2.6: Thu 26 Feb 2026 13:13:38 AEDT # Added Azure App Service Deployment HTTPs check # 14.2.7: Thu 26 Feb 2026 13:14:36 AEDT # Added Azure App Service Deployment Slot TLS version check # 14.2.8: Thu 26 Feb 2026 13:16:53 AEDT # Added Azure App Service Deployment Slot end to end TLS encryptions check # 14.2.9: Thu 26 Feb 2026 13:20:20 AEDT # Added Azure App Service Deployment Slot Remote Debugging check # 14.2.9: Thu 26 Feb 2026 13:27:03 AEDT # Added Azure App Service Deployment Slot Client Certificates check # 14.2.9: Thu 26 Feb 2026 13:28:00 AEDT # Added Azure App Service Deployment Slot Managed Identities check # 14.3.0: Thu 26 Feb 2026 13:28:23 AEDT # Added Azure App Service Deployment Slot Public Network Access check # 14.3.1: Thu 26 Feb 2026 13:39:41 AEDT # Added Azure App Service Deployment Slot VNet check # 14.3.2: Thu 26 Feb 2026 13:40:33 AEDT # Added Azure App Service Deployment Slot VNet Routing check # 14.3.3: Thu 26 Feb 2026 13:41:45 AEDT # Added Azure App Service Deployment Slot Cross-Origin Resource Sharing check # 14.3.4: Thu 26 Feb 2026 13:44:47 AEDT # Updates and improvements # 14.3.5: Thu 26 Feb 2026 15:46:47 AEDT # Added Azure Function App module # 14.3.6: Thu 26 Feb 2026 16:47:47 AEDT # Added Azure Function App function # 14.3.7: Thu 26 Feb 2026 16:48:47 AEDT # Added Azure Function App check for Java version # 14.3.8: Thu 26 Feb 2026 16:49:47 AEDT # Added Azure Function App check for Python version # 14.3.9: Thu 26 Feb 2026 16:50:47 AEDT # Added Azure Function App check for PHP version # 14.4.0: Thu 26 Feb 2026 16:51:47 AEDT # Added Azure Function App check for Basic Authentication Publishing Credentials # 14.4.1: Thu 26 Feb 2026 16:52:47 AEDT # Added Azure Function App check for FTP state # 14.4.2: Thu 26 Feb 2026 16:53:47 AEDT # Added Azure Function App check for HTTP version # 14.4.3: Thu 26 Feb 2026 16:54:47 AEDT # Added Azure Function App check for HTTPS only # 14.4.4: Thu 26 Feb 2026 16:55:47 AEDT # Added Azure Function App check for Minimum Inbound TLS Version # 14.4.5: Thu 26 Feb 2026 16:56:47 AEDT # Added Azure Function App check for end to end TLS encryption # 14.4.6: Thu 26 Feb 2026 16:57:47 AEDT # Added Azure Function App check for Remote Debugging # 14.4.7: Thu 26 Feb 2026 16:58:47 AEDT # Added Azure Function App check for Client Certificates # 14.4.8: Thu 26 Feb 2026 16:59:47 AEDT # Added Azure Function App check for Authentication # 14.4.9: Thu 26 Feb 2026 17:00:47 AEDT # Added Azure Function App check for Managed Identities # 14.5.0: Thu 26 Feb 2026 17:01:47 AEDT # Added Azure Function App check for Public Network Access # 14.5.1: Thu 26 Feb 2026 17:02:47 AEDT # Added Azure Function App check for App Service Plan SKU # 14.5.2: Thu 26 Feb 2026 17:03:47 AEDT # Added Azure Function App check for Private Endpoints # 14.5.3: Thu 26 Feb 2026 17:04:47 AEDT # Added Azure Function App check for Private DNS Zone # 14.5.4: Thu 26 Feb 2026 17:05:47 AEDT # Added Azure Function App check for Virtual Network Integration # 14.5.5: Thu 26 Feb 2026 17:06:47 AEDT # Added Azure Function App check for VNet Image Pull # 14.5.6: Thu 26 Feb 2026 17:07:47 AEDT # Added Azure Function App check for VNet Content Share # 14.5.7: Thu 26 Feb 2026 17:08:47 AEDT # Added Azure Function App check for Cross-Origin Resource Sharing # 14.5.8: Thu 26 Feb 2026 17:21:47 AEDT # Updates and improvements # 14.5.9: Thu 26 Feb 2026 17:38:47 AEDT # Added Azure Function App Deployment Slot audit module # 14.6.0: Thu 26 Feb 2026 17:39:47 AEDT # Added Azure Function App Deployment Slot function # 14.6.1: Thu 26 Feb 2026 17:40:47 AEDT # Added Azure Function App Deployment Slot check for Java version # 14.6.2: Thu 26 Feb 2026 17:41:47 AEDT # Added Azure Function App Deployment Slot check for Python version # 14.6.3: Thu 26 Feb 2026 17:42:47 AEDT # Added Azure Function App Deployment Slot check for PHP version # 14.6.4: Thu 26 Feb 2026 17:43:47 AEDT # Added Azure Function App Deployment Slot check for Basic Authentication Publishing Credentials # 14.6.5: Thu 26 Feb 2026 17:44:47 AEDT # Added Azure Function App Deployment Slot check for FTP state # 14.6.6: Thu 26 Feb 2026 17:45:47 AEDT # Added Azure Function App Deployment Slot check for HTTP version # 14.6.7: Thu 26 Feb 2026 17:46:47 AEDT # Added Azure Function App Deployment Slot check for HTTPS only # 14.6.8: Thu 26 Feb 2026 17:47:47 AEDT # Added Azure Function App Deployment Slot check for Minimum Inbound TLS Version # 14.6.9: Thu 26 Feb 2026 17:48:47 AEDT # Added Azure Function App Deployment Slot check for end to end TLS encryption # 14.7.0: Thu 26 Feb 2026 17:49:47 AEDT # Added Azure Function App Deployment Slot check for Remote Debugging # 14.7.1: Thu 26 Feb 2026 17:50:47 AEDT # Added Azure Function App Deployment Slot check for Client Certificates # 14.7.2: Thu 26 Feb 2026 17:51:47 AEDT # Added Azure Function App Deployment Slot check for Authentication # 14.7.3: Thu 26 Feb 2026 17:52:47 AEDT # Added Azure Function App Deployment Slot check for Managed Identities # 14.7.4: Thu 26 Feb 2026 17:53:47 AEDT # Added Azure Function App Deployment Slot check for Public Network Access # 14.7.5: Thu 26 Feb 2026 17:54:47 AEDT # Added Azure Function App Deployment Slot check for Virtual Network Integration # 14.7.6: Thu 26 Feb 2026 17:55:47 AEDT # Added Azure Function App Deployment Slot check for VNet Image Pull # 14.7.7: Thu 26 Feb 2026 17:56:47 AEDT # Added Azure Function App Deployment Slot check for VNet Content Share # 14.7.8: Thu 26 Feb 2026 17:57:47 AEDT # Added Azure Function App Deployment Slot check for Cross-Origin Resource Sharing # 14.7.9: Thu 26 Feb 2026 17:58:47 AEDT # Updates and improvements # 14.8.0: Fri 27 Feb 2026 11:31:09 AEDT # Added Azure Key Vault Certificates audit module # 14.8.1: Fri 27 Feb 2026 11:32:09 AEDT # Added Azure Key Vault Secrets audit module # 14.8.2: Fri 27 Feb 2026 11:33:09 AEDT # Updates and improvements # 14.8.3: Fri 27 Feb 2026 12:41:09 AEDT # Added Azure App Service ASE audit module # 14.8.4: Fri 27 Feb 2026 12:42:09 AEDT # Added Azure App Service ASE function # 14.8.5: Fri 27 Feb 2026 12:43:09 AEDT # Added Azure App Service ASE check for internal load balancing mode # 14.8.6: Fri 27 Feb 2026 12:50:11 AEDT # Added Azure App Service ASE check for ASE version # 14.8.7: Fri 27 Feb 2026 12:51:11 AEDT # Added Azure App Service ASE check for internal encryption # 14.8.8: Fri 27 Feb 2026 12:52:11 AEDT # Added Azure App Service ASE check for TLS 1.0 and 1.1 disabled # 14.8.9: Fri 27 Feb 2026 12:53:11 AEDT # Added Azure App Service ASE check for TLS cipher suite ordering configured # 14.9.0: Fri 27 Feb 2026 15:32:11 AEDT # Added Azure Container Instances audit module # 14.9.1: Fri 27 Feb 2026 15:33:11 AEDT # Added Azure Container Instances function # 14.9.2: Fri 27 Feb 2026 15:34:11 AEDT # Added Azure Container Instances check for Private Virtual Networks # 14.9.3: Fri 27 Feb 2026 15:35:11 AEDT # Added Azure Container Instances check for Managed Identity # 14.9.4: Fri 27 Feb 2026 16:05:11 AEDT # Added Azure CycleCloud audit module # 14.9.5: Fri 27 Feb 2026 16:22:11 AEDT # Added Azure Batch audit module # 14.9.6: Fri 27 Feb 2026 16:23:11 AEDT # Added Azure Batch function # 14.9.7: Fri 27 Feb 2026 16:24:11 AEDT # Added Azure Batch check for customer managed keys # 14.9.8: Fri 27 Feb 2026 16:25:11 AEDT # Added Azure Batch check for pool disk encryption # 14.9.9: Fri 27 Feb 2026 18:06:48 AEDT # Added Azure Batch check for local authentication methods # 15.0.0: Fri 27 Feb 2026 18:07:48 AEDT # Added Azure Batch check for private endpoints # 15.0.1: Fri 27 Feb 2026 18:08:48 AEDT # Added Azure Batch check for public network access # 15.0.2: Fri 27 Feb 2026 20:10:48 AEDT # Updates and improvements # 15.0.3: Sat 28 Feb 2026 11:47:48 AEDT # Added Azure Virtual Machines audit module # 15.0.4: Sat 28 Feb 2026 11:48:48 AEDT # Added Azure Virtual Machines function # 15.0.5: Sat 28 Feb 2026 11:49:48 AEDT # Updates and improvements # 15.0.6: Sat 28 Feb 2026 21:31:31 AEDT # Formatting fixes # 15.0.7: Mon 2 Mar 2026 11:44:44 AEDT # Formatting fixes # 15.0.8: Mon 2 Mar 2026 20:45:44 AEDT # Formatting fixes # 15.0.9: Wed 04 Mar 2026 17:28:10 AEDT # More formatting fixes # 15.1.0: Tue 10 Mar 2026 14:49:52 AEDT # Added switch value checking # 15.1.1: Tue 10 Mar 2026 16:38:52 AEDT # Improved Azure CLI extension checking # 15.1.2: Wed 11 Mar 2026 15:27:06 AEDT # Improved module listing # 15.1.3: Wed 11 Mar 2026 16:35:06 AEDT # Formatting fixes # 15.1.4: Thu 12 Mar 2026 08:06:53 AEDT # Typo fixes # 15.1.5: Thu 12 Mar 2026 13:08:36 AEDT # Formatting fixes # 15.1.6: Thu 12 Mar 2026 15:50:28 AEDT # Shellcheck fixes # 15.1.7: Thu 12 Mar 2026 17:29:28 AEDT # Formatting fixes # 15.1.8: Fri 13 Mar 2026 12:45:28 AEDT # Split out Azure WebApps Java version check # 15.1.9: Fri 13 Mar 2026 12:46:28 AEDT # Updated Azure WebApps value check # 15.2.0: Fri 13 Mar 2026 13:21:28 AEDT # Split out Azure WebApps Python version check # 15.2.1: Fri 13 Mar 2026 13:26:28 AEDT # Split out Azure WebApps PHP version check # 15.2.2: Fri 13 Mar 2026 13:27:28 AEDT # Split out Azure WebApps FTP state check # 15.2.3: Fri 13 Mar 2026 15:14:28 AEDT # Split out Azure WebApps Basic Authentication Publishing Credentials check # 15.2.4: Fri 13 Mar 2026 15:15:28 AEDT # Fixed Azure WebApps Basic Authentication Publishing Credentials check # 15.2.5: Fri 13 Mar 2026 16:36:28 AEDT # Split out Azure WebApps HTTP values check # 15.2.6: Fri 13 Mar 2026 16:57:28 AEDT # Split out Azure WebApps TLS values check # 15.2.7: Fri 13 Mar 2026 17:23:28 AEDT # Split out Azure WebApps Remote Debugging check # 15.2.8: Fri 13 Mar 2026 17:36:28 AEDT # Split out Azure WebApps Client Certificates check # 15.2.9: Fri 13 Mar 2026 17:43:28 AEDT # Split out Azure WebApps Authentication check # 15.3.0: Fri 13 Mar 2026 17:46:28 AEDT # Split out Azure WebApps Managed Identities check # 15.3.1: Fri 13 Mar 2026 17:54:28 AEDT # Split out Azure WebApps Public Network Access check # 15.3.2: Fri 13 Mar 2026 17:58:28 AEDT # Split out Azure WebApps Private DNS Zones check # 15.3.3: Fri 13 Mar 2026 18:14:28 AEDT # Split out Azure WebApps Virtual Network Integration check # 15.3.4: Fri 13 Mar 2026 18:22:28 AEDT # Split out Azure WebApps VNet checks # 15.3.5: Fri 13 Mar 2026 18:43:28 AEDT # Split out Azure WebApps CORS check # 15.3.6: Fri 13 Mar 2026 18:44:28 AEDT # Split out Azure WebApps Private Endpoint check # 15.3.7: Fri 13 Mar 2026 18:45:28 AEDT # Fixed Azure Private Endpoint check # 15.3.8: Fri 13 Mar 2026 20:46:28 AEDT # Fixed Azure App Service Plan SKU check # 15.3.9: Fri 13 Mar 2026 20:47:28 AEDT # Split out Azure App Service Plan SKU check # 15.4.0: Mon 16 Mar 2026 12:38:14 AEDT # Split out Azure App Service Deployment Slot Java version check # 15.4.1: Mon 16 Mar 2026 13:47:02 AEDT # Split azure directories into sub directories # 15.4.2: Mon 16 Mar 2026 14:43:03 AEDT # Split out Azure App Service Deployment Slot Python version check # 15.4.3: Mon 16 Mar 2026 15:14:03 AEDT # Split out Azure App Service Deployment Slot PHP version check # 15.4.4: Mon 16 Mar 2026 15:15:03 AEDT # Split out Azure App Service Deployment Slot Basic Auth check # 15.4.5: Mon 16 Mar 2026 15:31:03 AEDT # Split out Azure App Service Deployment Slot FTP State check # 15.4.6: Mon 16 Mar 2026 15:52:03 AEDT # Split out Azure App Service Deployment Slot HTTP Version check # 15.4.7: Mon 16 Mar 2026 15:59:11 AEDT # Split out Azure App Service Deployment Slot HTTPS Only check # 15.4.8: Mon 16 Mar 2026 16:07:11 AEDT # Split out Azure App Service Deployment Slot TLS values check # 15.4.9: Mon 16 Mar 2026 16:51:41 AEDT # Split out Azure App Service Deployment Slot Remote Debugging check # 15.5.0: Mon 16 Mar 2026 16:56:41 AEDT # Split out Azure App Service Deployment Slot Client Certificates check # 15.5.1: Mon 16 Mar 2026 17:04:41 AEDT # Split out Azure App Service Deployment Slot Managed Identities check # 15.5.2: Mon 16 Mar 2026 17:08:41 AEDT # Split out Azure App Service Deployment Slot Public Network Access check # 15.5.3: Mon 16 Mar 2026 17:12:41 AEDT # Split out Azure App Service Deployment Slot Virtual Network Integration check # 15.5.4: Mon 16 Mar 2026 17:15:41 AEDT # Split out Azure App Service Deployment Slot VNet Image Pull check # 15.5.5: Mon 16 Mar 2026 17:16:41 AEDT # Split out Azure App Service Deployment Slot VNet Content Share check # 15.5.6: Mon 16 Mar 2026 17:22:25 AEDT # Split out Azure App Service Deployment Slot CORS check # 15.5.7: Mon 16 Mar 2026 17:27:25 AEDT # Split out Azure App Service Deployment Slot Private Endpoints check # 15.5.8: Mon 16 Mar 2026 19:31:25 AEDT # Split out Azure Function App Deployment Slots Java version check # 15.5.9: Mon 16 Mar 2026 19:55:25 AEDT # Split out Azure Function App Deployment Slots Python version check # 15.6.0: Mon 16 Mar 2026 20:09:13 AEDT # Split out Azure Function App Deployment Slots Basic Authentication Publishing Credentials check # 15.6.1: Mon 16 Mar 2026 20:15:13 AEDT # Split out Azure Function App Deployment Slots FTP State check # 15.6.2: Mon 16 Mar 2026 20:20:13 AEDT # Split out Azure Function App Deployment Slots HTTP Version and HTTPS Only check # 15.6.3: Mon 16 Mar 2026 21:43:13 AEDT # Split out Azure Function App Deployment Slots TLS values check # 15.6.4: Mon 16 Mar 2026 21:44:13 AEDT # Formatting fixes for Azure Function App Deployment Slots # 15.6.5: Mon 17 Mar 2026 22:20:13 AEDT # Formatting fixes for Azure App Service Deployment Slots # 15.6.6: Mon 17 Mar 2026 22:28:13 AEDT # Split out Azure Function App Deployment Slots Remote Debugging check # 15.6.7: Mon 17 Mar 2026 22:32:13 AEDT # Split out Azure Function App Deployment Slots Client Certificates check # 15.6.8: Mon 17 Mar 2026 22:36:13 AEDT # Split out Azure Function App Deployment Slots Managed Identities check # 15.6.9: Mon 17 Mar 2026 22:40:13 AEDT # Split out Azure Function App Deployment Slots Public Network Access check # 15.7.0: Mon 17 Mar 2026 22:44:13 AEDT # Split out Azure Function App Deployment Slots Virtual Network Integration and VNet check # 15.7.1: Mon 17 Mar 2026 22:48:13 AEDT # Split out Azure Function App Deployment Slots CORS check # 15.7.2: Mon 17 Mar 2026 22:52:13 AEDT # Split out Azure Function App Deployment Slots Private Endpoints check # 15.7.3: Mon 17 Mar 2026 22:56:13 AEDT # Directory structure clean up # 15.7.4: Tue 17 Mar 2026 11:00:33 AEDT # Split out Azure Function App Java versions check # 15.7.5: Tue 17 Mar 2026 11:02:33 AEDT # Split out Azure Function App Python versions check # 15.7.6: Tue 17 Mar 2026 13:35:33 AEDT # Split out Azure Function App Basic Authentication Publishing Credentials check # 15.7.7: Tue 17 Mar 2026 13:46:33 AEDT # Split out Azure Function App FTP State check # 15.7.8: Tue 17 Mar 2026 14:30:13 AEDT # Split out Azure Function App HTTP values check # 15.7.9: Tue 17 Mar 2026 14:37:13 AEDT # Split out Azure Function App TLS values check # 15.8.0: Wed 18 Mar 2026 15:13:13 AEDT # Split out Azure Function App Remote Debugging check # 15.8.1: Wed 18 Mar 2026 15:17:40 AEDT # Split out Azure Function App Client Certificates check # 15.8.2: Wed 18 Mar 2026 15:35:40 AEDT # Split out Azure Function App Service Authentication check # 15.8.3: Wed 18 Mar 2026 15:52:40 AEDT # Split out Azure Function App Managed Identities check # 15.8.4: Wed 18 Mar 2026 15:57:40 AEDT # Split out Azure Function App Public Network Access check # 15.8.5: Wed 18 Mar 2026 16:09:40 AEDT # Split out Azure Function App Virtual Network Integration and VNet checks # 15.8.6: Wed 18 Mar 2026 16:13:40 AEDT # Split out Azure Function App Cross-Origin Resource Sharing check # 15.8.7: Wed 18 Mar 2026 16:31:40 AEDT # Function name cleanup # 15.8.8: Thu 19 Mar 2026 14:04:02 AEDT # Cleaned up AWS module directory structure # 15.8.9: Thu 19 Mar 2026 17:34:02 AEDT # Added platform check to XD/NX Support check # 15.9.0: Thu 19 Mar 2026 18:06:02 AEDT # Added percentage calculation to print_info # 15.9.1: Thu 19 Mar 2026 21:21:45 AEDT # Fixed Bluetooth check ================================================ FILE: docker-compose.yml ================================================ version: '3' services: test-shell: image: "${OS_NAME}:${OS_VERSION}" volumes: - ".:/lunar" command: "/bin/bash" test-audit: image: "${OS_NAME}:${OS_VERSION}" volumes: - ".:/lunar" command: bash -c "/lunar/lunar.sh -a" ================================================ FILE: functions/aix/check_auditctl.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_auditctl # # Check whether a executable, file or directory is being audited #. check_auditctl () { check_file="${1}" audit_tag="${2}" print_function "check_auditctl" if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then secure_string="Auditing is enabled on file \"${check_file}\"" insecure_string="Auditing is not enabled on file \"${check_file}\"" check_message "${secure_string}" get_command="auditctl -l | grep ${check_file}" set_command="auditctl -w ${file} -p wa -k ${audit_tag}" if [ -e "${check_file}" ]; then check=$( auditctl -l | grep "${check_file}" ) if [ -z "${check}" ]; then if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="auditctl_file_check_${ansible_counter}" echo "" echo "- name: Checking ${secure_string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Enable Auditing for ${file}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi inc_insecure "${insecure_string}" lock_command="${set_command}" lock_message="${secure_string}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "${secure_string}" fi fi fi fi } ================================================ FILE: functions/aix/check_chsec.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_chsec # # Function to check sec under AIX #. check_chsec() { if [ "${os_name}" = "AIX" ]; then sec_file="${1}" sec_stanza="${2}" parameter_name="${3}" correct_value="${4}" print_function "check_chsec" log_file="${sec_file}_${sec_stanza}_${parameter_name}.log" get_command="lssec -f ${sec_file} -s ${sec_stanza} -a ${parameter_name} |awk '{print \$2}' |cut -f2 -d=" set_command="chsec -f ${sec_file} -s ${sec_stanza} -a ${parameter_name}=${correct_value}" if [ "${audit_mode}" != 2 ]; then string="Security Policy for \"${parameter_name}\" is set to \"${correct_value}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_chsec_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi actual_value=$( eval "${get_command}" ) if [ "${actual_value}" != "${correct_value}" ]; then update_log "${log_file}" "chsec -f ${sec_file} -s ${sec_stanza} -a ${parameter_name}=${actual_value}" inc_insecure "Security Policy for \"${parameter_name}\" is not set to \"${correct_value}\"" lock_command="chsec -f ${sec_file} -s ${sec_stanza} -a ${parameter_name}=${correct_value}" lock_message="Security Policy for \"${parameter_name}\" to \"${correct_value}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "Password Policy for \"${parameter_name}\" is set to \"${correct_value}\"" fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then previous_value=$( cut -f2 -d= "${log_file}" ) if [ "${previous_value}" != "${actual_value}" ]; then restore_message="Restoring: Password Policy for \"${parameter_name}\" to \"${previous_value}\"" restore_command="sh < ${log_file}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi } ================================================ FILE: functions/aix/check_chuser.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_chuser # # Function to check sec under AIX #. check_chuser() { if [ "${os_name}" = "AIX" ]; then sec_file="${1}" parameter_name="${2}" correct_value="${3}" group_name="${4}" group_value="${5}" user_name="${6}" print_function "check_chuser" log_file="${sec_file}_${parameter_name}_${group_name}.log" get_command="lssec -f ${sec_file} -s ${sec_stanza} -a ${parameter_name} |awk '{print \$2}' |cut -f2 -d=" set_command="chsec -f ${sec_file} -s ${sec_stanza} -a ${parameter_name}=${correct_value}" if [ "${audit_mode}" != 2 ]; then string="Security Policy for \"${parameter_name}\" is set to \"${correct_value}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_chuser_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi actual_value=$( eval "${get_command}" ) if [ "${actual_value}" != "${correct_value}" ]; then update_log "${log_file}" "chuser ${parameter_name}=${correct_value} ${group_name}=${group_value} ${user_name}" inc_insecure "Security Policy for \"${parameter_name}\" is not set to \"${correct_value}\" for \"${user_name}\"" lock_command="chuser ${parameter_name}=${correct_value} ${group_name}=${group_value} ${user_name}" lock_message="Security Policy for \"${parameter_name}\" to \"${correct_value}\"" run_lockdown "${lock_command}" "${lock_message}" else inc_secure "Security Policy for \"${parameter_name}\" is set to \"${correct_value}\" for \"${user_name}\"" fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then previous_value=$( cut -f2 -d= "${log_file}" ) if [ "${previous_value}" != "${actual_value}" ]; then restore_message="Restoring: Password Policy for \"${parameter_name}\" to \"${previous_value}\"" restore_command="sh < ${log_file}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi } ================================================ FILE: functions/aix/check_itab.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2086 # check_itab # # Function to check inittab under AIX #. check_itab() { if [ "${os_name}" = "AIX" ]; then service_name="${1}" correct_value="${2}" print_function "check_itab" log_file="${service_name}.log" actual_value=$( lsitab "${service_name}" | cut -f1 -d: ) if [ "${correct_value}" = "off" ]; then if [ "${actual_status}" != "${service_name}" ]; then actual_value="off" fi fi if [ "${audit_mode}" != 2 ]; then string="Service \"${service_name}\" is not \"${correct_value}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " aix_inittab:" echo " namw: ${service_name}" echo " state: ${correct_value}" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${actual_value}" != "${correct_value}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Service \"${service_name}\" is \"${correct_value}\"" if [ "${correct_value}" = "off" ]; then fix_message "rmitab $( lsitab | grep \"^${service_name}\" )" else fix_message "chitab \"${correct_value}\"" fi fi if [ "${audit_mode}" = 0 ]; then log_file="${work_dir}/${log_file}" lock_message="Service \"${service_name}\" to \"${correct_value}\"" if [ "${correct_value}" = "off" ]; then update_log "${log_file}" "${actual_value}" lock_command="rmitab ${service_name}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else if [ "${actual_value}" = "off" ]; then update_log "${log_file}" "off" lock_command="mkitab ${correct_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else update_log "${log_file}" "${actual_value}" lock_command="chitab ${correct_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi else inc_secure "Service \"${service_name}\" is \"${correct_value}\"" fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then previous_value=$( cat "${log_file}" ) if [ "${previous_value}" != "${actual_value}" ]; then restore_message="Service \"${service_name}\" to \"${previous_value}\"" if [ "${previous_value}" = "off" ]; then restore_command="rmitab ${service_name}" else if [ "${actual_status}" = "off" ]; then restore_command="mkitab ${service_name} ${previous_value}" else restore_command="chitab ${service_name} ${previous_value}" fi fi execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi } ================================================ FILE: functions/aix/check_lslpp.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_lslpp # # Check if an AIX package is installed, if so install_check will be be set with # name of rpm, otherwise it will be empty #. check_lslpp () { package_name="${1}" print_function "check_lslpp" if [ "${os_name}" = "AIX" ]; then lslpp_check="lslpp -L |grep \"${package_name}\"" fi } ================================================ FILE: functions/aix/check_no.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_no # # Function to check no under AIX #. check_no() { if [ "${os_name}" = "AIX" ]; then parameter_name="${1}" correct_value="${2}" print_function "check_no" log_file="${parameter_name}.log" get_command="no -a |grep '${parameter_name} ' |cut -f2 -d= |sed 's/ //g' |grep '${correct_value}'" set_command="no -p -o ${parameter_name}=${correct_value}" actual_value=$( eval "${get_command}" ) if [ "${audit_mode}" != 2 ]; then string="Parameter \"${parameter_name}\" is \"${correct_value}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_no_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${actual_value}" != "${correct_value}" ]; then inc_insecure "Parameter \"${parameter_name}\" is not \"${correct_value}\"" update_log "${log_file}" "${actual_value}" lock_command="no -p -o ${parameter_name}=${correct_value}" lock_message="Parameter \"${parameter_name}\" to \"${correct_value}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "Parameter \"${parameter_name}\" is \"${correct_value}\"" fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then previous_value=$( cat "${log_file}" ) if [ "${previous_value}" != "${actual_value}" ]; then restore_message="Parameter \"${parameter_name}\" to \"${previous_value}\"" restore_command="no -p -o ${parameter_name}=${previous_value}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi } ================================================ FILE: functions/aix/check_pwpolicy.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_pwpolicy # # Function to check pwpolicy output under OS X #. check_pwpolicy() { if [ "${os_name}" = "Darwin" ]; then parameter_name="${1}" correct_value="${2}" print_function "check_pwpolicy" log_file="${parameter_name}.log" if [ "${audit_mode}" != 2 ]; then string="Password Policy for \"${parameter_name}\" is set to \"${correct_value}\"" check_message "${string}" if [ "${os_version}" -ge 12 ]; then policy_command="pwpolicy -getglobalpolicy |tr ' ' '\\\n' |grep ${parameter_name} |cut -f2 -d=" else if [ "${managed_node}" = "Error" ]; then policy_command="sudo pwpolicy -n /Local/Default -getglobalpolicy ${parameter_name} 2>&1 |cut -f2 -d=" else policy_command="sudo pwpolicy -n -getglobalpolicy ${parameter_name} 2>&1 |cut -f2 -d=" fi fi actual_value=$( eval "${policy_command}" ) if [ "${actual_value}" != "${correct_value}" ]; then lock_message="Password Policy for \"${parameter_name}\" to \"${correct_value}\"" inc_insecure "Password Policy for \"${parameter_name}\" is not set to \"${correct_value}\"" if [ "${os_version}" -ge 12 ]; then lock_command="sudo pwpolicy -setglobalpolicy ${parameter_name}=${correct_value}" update_log "${log_file}" "${actual_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else if [ "${managed_node}" = "Error" ]; then lock_command="pwpolicy -n /Local/Default -setglobalpolicy ${parameter_name}=${correct_value}" update_log "${log_file}" "${actual_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else lock_command="pwpolicy -n -setglobalpolicy ${parameter_name}=${correct_value}" update_log "${log_file}" "${actual_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_pwpolicy_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${policy_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${lock_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Password Policy for \"${parameter_name}\" is set to \"${correct_value}\"" fi fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then previous_value=$( cat "${log_file}" ) restore_message="Password Policy for \"${parameter_name}\" to \"${previous_value}\"" if [ "${previous_value}" != "${actual_value}" ]; then if [ "${os_version}" -ge 12 ]; then restore_command="pwpolicy -setglobalpolicy ${parameter_name}=${previous_value}" execute_restore "${restore_command}" "${restore_message}" "sudo" else if [ "${managed_node}" = "Error" ]; then restore_command="pwpolicy -n /Local/Default -setglobalpolicy ${parameter_name}=${previous_value}" execute_restore "${restore_command}" "${restore_message}" "sudo" else restore_command="pwpolicy -n -setglobalpolicy ${parameter_name}=${previous_value}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi fi fi } ================================================ FILE: functions/aix/check_rctcp.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_rctcp # # Function to check rctcp under AIX #. check_rctcp() { if [ "${os_name}" = "AIX" ]; then service_name="${1}" correct_value="${2}" print_function "check_rctcp" if [ "${correct_value}" = "off" ]; then status_value="disabled" else status_value="enabled" fi log_file="${service_name}.log" actual_value=$( lssrc -a | grep "${service_name} " | awk '{print $4}' ) if [ "${actual_value}" = "active" ]; then actual_value="off" else actual_value="on" fi if [ "${audit_mode}" != 2 ]; then string="Service \"${service_name}\" is \"${correct_value}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " service:" echo " name: ${service_name}" echo " enabled: ${status_value}" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${actual_value}" != "${correct_value}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Service \"${service_name}\" is not \"${correct_value}\"" if [ "${correct_value}" = "off" ]; then fix_message "chrctcp -d ${service_name}" fix_message "stopsrc -s ${service_name}" fix_message "sed \"/${service_name} /s/^/#/g\" < /etc/rc.tcpip > ${temp_file}" fix_message "cat ${temp_file} > /etc/rc.tcpip" fix_message "rm ${temp_file}" else fix_message "chrctcp -a ${service_name}" fix_message "startsrc -s ${service_name}" fix_message "sed \"/${service_name} /s/^#.//g\" < /etc/rc.tcpip > ${temp_file}" fix_message "cat ${temp_file} > /etc/rc.tcpip" fix_message "rm ${temp_file}" fi fi if [ "${audit_mode}" = 0 ]; then log_file="${work_dir}/${log_file}" set_message "Service \"${service_name}\" to \"${correct_value}\"" echo "${actual_value}" > "${log_file}" if [ "${correct_value}" = "off" ]; then chrctcp -d "${service_name}" stopsrc -s "${service_name}" sed "/${service_name} /s/^/#/g" < /etc/rc.tcpip > "${temp_file}" cat "${temp_file}" > /etc/rc.tcpip rm "${temp_file}" else chrctcp -a "${service_name}" startsrc -s "${service_name}" sed "/${service_name} /s/^#.//g" < /etc/rc.tcpip > "${temp_file}" cat "${temp_file}" > /etc/rc.tcpip rm "${temp_file}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Service \"${service_name}\" is \"${correct_value}\"" fi fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then previous_value=$( cat "${log_file}" ) if [ "${previous_value}" != "${actual_value}" ]; then restore_message "Service \"${service_name}\" to \"${previous_value}\"" if [ "${previous_value}" = "off" ]; then chrctcp -d "${service_name}" stopsrc -s "${service_name}" sed "/${service_name} /s/^/#/g" < /etc/rc.tcpip > "${temp_file}" cat "${temp_file}" > /etc/rc.tcpip rm "${temp_file}" else chrctcp -a "${service_name}" startsrc -s "${service_name}" sed "/${service_name} /s/^#.//g" < /etc/rc.tcpip > "${temp_file}" cat "${temp_file}" > /etc/rc.tcpip rm "${temp_file}" fi fi fi fi fi } ================================================ FILE: functions/aix/check_subserver.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_subserver # # Function to check subserver under AIX #. check_subserver() { if [ "${os_name}" = "AIX" ]; then service_name="${1}" protocol_name="${2}" correct_value="${3}" print_function "check_subserver" log_file="${service_name}.log" actual_value=$( grep "${service_name} " /etc/inetd.conf | grep "${protocol_name} " | grep -v "^#" | awk "{print $1}" ) if [ "${actual_value}" != "${service_name}" ]; then actual_value="off" else actual_value="on" fi if [ "${audit_mode}" != 2 ]; then string="Service \"${service_name}\" Protocol \"${protocol_name}\" is \"${correct_value}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " service:" echo " name: ${service_name}" echo " enabled: ${enabled}" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${actual_value}" != "${service_name}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Service \"${service_name}\" Protocol \"${protocol_name}\" is not \"${correct_value}\"" if [ "${correct_value}" = "off" ]; then fix_command="chsubserver -r inetd -C /etc/inetd.conf -d -v \"${service_name}\" -p \"${protocol_name}\"" fix_message "${fix_command}" else fix_command="chsubserver -r inetd -C /etc/inetd.conf -a -v \"${service_name}\" -p \"${protocol_name}\"" fix_message "${fix_command}" fi fi if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${actual_value}" lock_message="Service \"${service_name}\" Protocol \"${protocol_name}\" to \"${correct_value}\"" if [ "${correct_value}" = "off" ]; then lock_command="chsubserver -r inetd -C /etc/inetd.conf -d -v ${service_name} -p ${protocol_name}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else lock_command="chsubserver -r inetd -C /etc/inetd.conf -a -v ${service_name} -p ${protocol_name}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi else inc_secure "Service \"${service_name}\" Protocol \"${protocol_name}\" is \"${correct_value}\"" fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then previous_value=$( cat "${log_file}" ) if [ "${previous_value}" != "${actual_value}" ]; then restore_message="Service \"${service_name}\" Protocol \"${protocol_name}\" to \"${previous_value}\"" if [ "${previous_value}" = "off" ]; then restore_command="chsubserver -r inetd -C /etc/inetd.conf -d -v ${service_name} -p ${protocol_name}" execute_restore "${restore_command}" "${restore_message}" "sudo" else restore_command="chsubserver -r inetd -C /etc/inetd.conf -a -v ${service_name} -p ${protocol_name}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi fi } ================================================ FILE: functions/aix/check_trust.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_trust # # Function to check trustchk under AIX #. check_trust() { if [ "${os_name}" = "AIX" ]; then parameter_name="${1}" correct_value="${2}" print_function "check_trust" log_file="trustchk_${parameter_name}.log" actual_value=$( trustchk -p "${parameter_name}" | cut -f2 -d= ) policy_command="trustchk -p ${parameter_name} | cut -f2 -d= | grep ${correct_value}" lock_command="trustchk -p ${parameter_name}=${correct_value}" if [ "${audit_mode}" != 2 ]; then string="Trusted Execution setting for \"${parameter_name}\" is set to \"${correct_value}\"" check_message "${string}" if [ "${actual_value}" != "${correct_value}" ]; then inc_insecure "Trusted Execution setting for \"${parameter_name}\" is not set to \"${correct_value}\"" update_log "${log_file}" "trustchk-p ${parameter_name}=${actual_value}" lock_message="Trusted Execution setting for \"${parameter_name}\" to \"${correct_value}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "Password Policy for \"${parameter_name}\" is set to \"${correct_value}\"" fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_trust_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${policy_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${lock_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then previous_value=$( cut -f2 -d= "${log_file}" ) if [ "${previous_value}" != "${actual_value}" ]; then restore_command="sh < ${log_file}" restore_message="Password Policy for \"${parameter_name}\" to \"${previous_value}\"" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi } ================================================ FILE: functions/aws/audit_aws.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # funct_audit_aws # # Audit AWS #. funct_audit_aws () { audit_mode="${1}" print_function "funct_audit_aws" check_environment check_aws audit_aws_all print_results } # funct_audit_aws # # Audit AWS REC #. funct_audit_aws_rec () { audit_mode="${1}" print_function "funct_audit_aws_rec" check_environment check_aws audit_aws_rec_all print_results } # audit_aws_all # # Audit AWS all # # Run various AWS audit tests # # This requires the AWS CLI to be installed and configured #. audit_aws_all () { print_function "audit_aws_all" audit_aws_iam audit_aws_mfa audit_aws_access_keys audit_aws_creds audit_aws_iam_policies audit_aws_password_policy audit_aws_support_role audit_aws_monitoring audit_aws_logging audit_aws_keys audit_aws_config audit_aws_sns audit_aws_vpcs audit_aws_sgs audit_aws_certs audit_aws_dns audit_aws_ec2 audit_aws_es audit_aws_elb audit_aws_s3 audit_aws_ses audit_aws_rds audit_aws_cf audit_aws_ec audit_aws_cdn audit_aws_redshift audit_aws_inspector } ================================================ FILE: functions/aws/audit_aws_rec_all.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # Audit AWS # # Run various AWS audit recommended tests # # This comes from sources like Cloud Conformity # # https://www.cloudconformity.com/conformity-rules/ # # This requires the AWS CLI to be installed and configured #. audit_aws_rec_all () { print_function "audit_aws_rec_all" audit_aws_rec_ec2 audit_aws_rec_es audit_aws_rec_dynamodb audit_aws_rec_elb audit_aws_rec_vpcs audit_aws_rec_rds audit_aws_rec_ec audit_aws_rec_monitoring audit_aws_rec_redshift audit_aws_rec_inspector } ================================================ FILE: functions/aws/check_aws_open_port.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_aws_open_port # # Check AWS Security Groups for open ports, i.e. CIDR of 0.0.0.0/0 # # This requires the AWS CLI to be installed and configured #. check_aws_open_port () { sg="${1}" port="${2}" protocol="${3}" service="${4}" app="${5}" instance="${6}" print_function "check_aws_open_port" command="aws ec2 describe-security-groups --region \"${aws_region}\" --group-ids \"${sg}\" --filters \"Name=ip-permission.to-port,Values=${port}\" \"Name=ip-permission.cidr,Values=0.0.0.0/0\" \"Name=ip-permission.protocol,Values=${protocol}\" --output text" command_message "${command}" open_port=$( eval "${command}" ) if [ "${app}" = "none" ]; then string="Security Group \"${sg}\" does not have service \"${service}\" on port \"${port}\" open to the world" else string="Application \"${app}\" with instance \"${instance}\" with Security Group \"${sg}\" does not have \"${service}\" on port \"${port}\" open to the world" fi check_message "${string}" if [ ! "${open_port}" ]; then inc_secure "${string}" else if [ "${app}" = "none" ]; then string="Security Group \"${sg}\" has service \"${service}\" on port \"${port}\" open to the world" else string="Application \"$app\" with instance \"${instance}\" with Security Group \"${sg}\" has \"${service}\" on port \"${port}\" open to the world" fi inc_insecure "${string}" lock_command="aws ec2 revoke-security-group-ingress --region ${aws_region} --group-name ${sg} --protocol ${protocol} --port ${port} --cidr 0.0.0.0/0" lock_message="${string}" run_lockdown "${lock_command}" "${lock_message}" fi } ================================================ FILE: functions/aws/check_aws_password_policy.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_aws_password_policy # # Check AWS Password Policy # # This requires the AWS CLI to be installed and configured #. check_aws_password_policy () { param="${1}" value="${2}" switch="${3}" print_function "check_aws_password_policy" command="aws iam get-account-password-policy 2> /dev/null | grep \"${param}\"" command_message "${command}" policy=$( eval "${command}" ) cli_fix="aws iam update-account-password-policy ${switch}" command="grep \"${param}\" \"${policy}\" | cut -f2 -d: | sed \"s/ //g\" | sed \"s/,//g\"" command_message "${command}" check=$( eval "${command}" ) secure_string="The password policy has \"${param}\" set to \"${value}\"" insecure_string="The password policy does not has \"${param}\" set to \"${value}\"" verbose_message "${secure_string}" "check" if [ "${check}" = "${value}" ]; then inc_secure "${secure_string}" else inc_insecure "${insecure_string}" lock_command="${cli_fix}" lock_message="IAM Account password policy parameter \"${param}\" to \"${value}\"" run_lockdown "${lock_command}" "${lock_message}" fi } ================================================ FILE: functions/azure/compute/batch/check_azure_batch_pool_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_batch_pool_value # # Check Azure Batch Pool value # # This requires the Azure CLI to be installed and configured #. check_azure_batch_pool_value () { description="${1}" pool_id="${2}" query_string="${4}" function="${5}" correct_value="${6}" set_name="${7}" set_value="${8}" print_function "check_azure_batch_pool_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi check_message "${description} for Batch Pool \"${pool_id}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" command="az batch pool show --id ${pool_id} --query '${query_string}' --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then secure_message "${description} for Batch Pool \"${pool_id}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" else insecure_message "${description} for Batch Pool \"${pool_id}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then fix_message "az batch pool set --id \"${pool_id}\" ${set_name} \"${set_value}\"" fi fi } ================================================ FILE: functions/azure/compute/batch/check_azure_batch_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_batch_value # # Check Azure Batch value # # This requires the Azure CLI to be installed and configured #. check_azure_batch_value () { description="${1}" batch_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" set_name="${7}" set_value="${8}" print_function "check_azure_batch_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi check_message "${description} for Batch Account \"${batch_name}\" in resource group \"${resource_group}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" command="az batch account show --name ${batch_name} --resource-group ${resource_group} --query '${query_string}' --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then secure_message "${description} for Batch Account \"${batch_name}\" in resource group \"${resource_group}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" else insecure_message "${description} for Batch Account \"${batch_name}\" in resource group \"${resource_group}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then fix_message "az batch account set --name \"${batch_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" fi fi } ================================================ FILE: functions/azure/compute/container/check_azure_container_instance_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_container_instance_value # # Check Azure Container Instance value # # This requires the Azure CLI to be installed and configured #. check_azure_container_instance_value () { description="${1}" container_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" print_function "check_azure_container_instance_value" check_message "${description} for Container Instance \"${container_name}\" in resource group \"${resource_group}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" command="az container show --name ${container_name} --resource-group ${resource_group} --query '${query_string}' --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then secure_message "${description} for Container Instance \"${container_name}\" in resource group \"${resource_group}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" else insecure_message "${description} for Container Instance \"${container_name}\" in resource group \"${resource_group}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az container update --name \"${container_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az container update --name \"${container_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${correct_value}\"" ;; esac fi fi } ================================================ FILE: functions/azure/compute/function/check_azure_function_app_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_function_app_value # # Check Azure Function App value # # This requires the Azure CLI to be installed and configured #. check_azure_function_app_value () { description="${1}" app_id="${2}" resource_group="${3}" sub_function="${4}" resource_type="${5}" resource_name="${6}" query_string="${7}" function="${8}" correct_value="${9}" set_name="${10}" set_value="${11}" print_function "check_azure_function_app_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi app_name=$( basename "${app_id}" ) check_message "Azure Function App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" if [ "${sub_function}" = "auth" ]; then command="az webapp auth show --name \"${app_name}\" --resource-group \"${resource_group}\" --query \"${query_string}\" --output tsv 2> /dev/null" else command="az functionapp show --id \"${app_id}\" --query \"${query_string}\" --output tsv 2> /dev/null" fi command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Function App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Function App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "virtualNetworkSubnetId" ]; then fix_message "az functionapp vnet-integration add --resource-group --name --vnet --subnet " fi if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --resource-group \"${resource_group}\" --name \"${resource_name}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}\" ${set_name} \"${set_value}\"" ;; "auth") fix_message "az webapp auth update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; "identity") fix_message "az functionapp identity assign --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az functionapp config set --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; esac ;; *) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --resource-group \"${resource_group}\" --name \"${resource_name}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}\" --set \"${set_name}\"=\"${set_value}\"" ;; "auth") fix_message "az webapp auth update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; "identity") fix_message "az functionapp identity assign --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; *) fix_message "az functionapp config set --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure Function App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "virtualNetworkSubnetId" ]; then fix_message "az functionapp vnet-integration add --resource-group --name --vnet --subnet " fi if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --resource-group \"${resource_group}\" --name \"${resource_name}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}\" ${set_name} \"${set_value}\"" ;; "auth") fix_message "az webapp auth update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; "identity") fix_message "az functionapp identity assign --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az functionapp config set --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; esac ;; *) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --resource-group \"${resource_group}\" --name \"${resource_name}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}\" --set \"${set_name}\"=\"${set_value}\"" ;; "auth") fix_message "az webapp auth update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; "identity") fix_message "az functionapp identity assign --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; *) fix_message "az functionapp config set --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac ;; esac fi else inc_secure "Azure App Service App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${set_value}\"" fi fi } ================================================ FILE: functions/azure/compute/function/check_azure_function_deployment_slot_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_function_deployment_slot_value # # Check Azure Function Deployment Slot value # # This requires the Azure CLI to be installed and configured #. check_azure_function_deployment_slot_value () { description="${1}" slot_id="${2}" app_name="${3}" resource_group="${4}" resource_type="${5}" resource_name="${6}" namespace_name="${7}" query_string="${8}" function="${9}" correct_value="${10}" set_name="${11}" set_value="${12}" print_function "check_azure_function_deployment_slot_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi slot_name=$( basename "${slot_id}" ) check_message "Azure Function Deployment Slot ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az resource show --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Function Deployment Slot ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Function Deployment Slot ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "virtualNetworkSubnetId" ]; then fix_message "az webapp vnet-integration add --resource-group --name --vnet --subnet " fi if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" ${set_name} \"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; esac ;; *) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" --set \"${set_name}\"=\"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure App Service Deployment Slot ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "virtualNetworkSubnetId" ]; then fix_message "az webapp vnet-integration add --resource-group --name --vnet --subnet " fi if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" ${set_name} \"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; esac ;; *) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" --set \"${set_name}\"=\"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac ;; esac fi else inc_secure "Azure App Service App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${set_value}\"" fi fi } ================================================ FILE: functions/azure/compute/vm/check_azure_vm_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_vm_value # # Check Azure VM value # # This requires the Azure CLI to be installed and configured #. check_azure_vm_value () { description="${1}" vm_name="${2}" resource_group="${3}" parameter_name="${4}" function="${5}" correct_value="${6}" print_function "check_azure_vnet_value" check_message "Azure VM \"${vm_name}\" in Resource Group \"${resource_group}\" has \"${parameter_name}\" ${function} to \"${correct_value}\"" command="az vm show --name \"${vm_name}\" --resource-group \"${resource_group}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "ne" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure VM \"${vm_name}\" in Resource Group \"${resource_group}\" does not have \"${parameter_name}\" ${function} to \"${correct_value}\"" else inc_secure "Azure VM \"${vm_name}\" in Resource Group \"${resource_group}\" has \"${parameter_name}\" ${function} to \"${correct_value}\"" fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure VM \"${vm_name}\" in Resource Group \"${resource_group}\" has \"${parameter_name}\" ${function} to \"${correct_value}\"" else inc_insecure "Azure VM \"${vm_name}\" in Resource Group \"${resource_group}\" does not have \"${parameter_name}\" ${function} to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/compute/webapp/check_azure_app_service_app_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_app_service_app_value # # Check Azure App Service App value # # This requires the Azure CLI to be installed and configured #. check_azure_app_service_app_value () { description="${1}" app_id="${2}" app_name="${3}" resource_group="${4}" resource_type="${5}" query_string="${6}" function="${7}" correct_value="${8}" set_name="${9}" set_value="${10}" print_function "check_azure_app_service_app_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi check_message "Azure App Service App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" case "${resource_type}" in "auth|identity") command="az webapp ${resource_type} show --id \"${app_id}\" --query \"${query_string}\" --output tsv 2> /dev/null" ;; *) command="az webapp show --id \"${app_id}\" --query \"${query_string}\" --output tsv 2> /dev/null" ;; esac command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "" ]; then case "${query_string}" in *Version) inc_secure "Azure App Service App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not set" return ;; esac fi if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure App Service App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure App Service App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${actual_value}\" and not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "virtualNetworkSubnetId" ]; then fix_message "az webapp vnet-integration add --resource-group --name --vnet --subnet " fi if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --resource-type \"${resource_type}\" --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --id \"${app_id}\" ${set_name} \"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --id \"${app_id}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; esac ;; *) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --resource-type \"${resource_type}\" --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --id \"${app_id}\" --set \"${set_name}\"=\"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --id \"${app_id}\" --set \"${set_name}\"=\"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure App Service App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "virtualNetworkSubnetId" ]; then fix_message "az webapp vnet-integration add --resource-group --name --vnet --subnet " fi if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --resource-type \"${resource_type}\" --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --id \"${app_id}\" ${set_name} \"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --id \"${app_id}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; esac ;; *) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --resource-type \"${resource_type}\" --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --id \"${app_id}\" --set \"${set_name}\"=\"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --id \"${app_id}\" --set \"${set_name}\"=\"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac ;; esac fi else inc_secure "Azure App Service App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${set_value}\"" fi fi } ================================================ FILE: functions/azure/compute/webapp/check_azure_app_service_ase_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_app_service_ase_value # # Check Azure App Service ASE value # # This requires the Azure CLI to be installed and configured #. check_azure_app_service_ase_value () { description="${1}" ase_name="${2}" sub_name="${3}" parameter_name="${4}" function="${5}" correct_value="${6}" print_function "check_azure_app_service_ase_value" check_message "${description} for App Service ASE ${ase_name} parameter ${parameter_name} is ${function} to ${correct_value}" if [ -z "${sub_name}" ]; then command="az appservice ase show --name ${ase_name} --query \"${parameter_name}\" --output tsv" command_message "${command}" actual_value=$( eval "${command}" 2> /dev/null ) else if [ "${function}" = "has" ]; then command="az appservice ase show --name ${ase_name} --query \"[?contains(${sub_name}.name, '${parameter_name}')]\" --query \"value\" --output tsv | grep \"${correct_value}\"" command_message "${command}" actual_value=$( eval "${command}" 2> /dev/null ) if [ -z "${actual_value}" ]; then actual_value="${correct_value}" fi else command="az appservice ase show --name ${ase_name} --query \"[?contains(${sub_name}.name, '${parameter_name}')]\" --query \"value\" --output tsv" command_message "${command}" actual_value=$( eval "${command}" 2> /dev/null ) fi fi if [ "${function}" = "eq" ]; then if [ "${actual_value}" != "${correct_value}" ]; then insecure_message "${description} for App Service ASE ${ase_name} parameter ${parameter_name} is not ${correct_value}" else secure_message "${description} for App Service ASE ${ase_name} parameter ${parameter_name} is ${correct_value}" fi else if [ "${function}" = "ne" ]; then if [ "${actual_value}" = "${correct_value}" ]; then insecure_message "${description} for App Service ASE ${ase_name} parameter ${parameter_name} is ${correct_value}" else secure_message "${description} for App Service ASE ${ase_name} parameter ${parameter_name} is not ${correct_value}" fi fi fi } ================================================ FILE: functions/azure/compute/webapp/check_azure_app_service_deployment_slot_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_app_service_app_value # # Check Azure App Service App value # # This requires the Azure CLI to be installed and configured #. check_azure_app_service_app_value () { description="${1}" slot_id="${2}" app_name="${3}" resource_group="${4}" resource_type="${5}" resource_name="${6}" namespace_name="${7}" query_string="${8}" function="${9}" correct_value="${10}" set_name="${11}" set_value="${12}" print_function "check_azure_app_service_app_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi slot_name=$( basename "${slot_id}" ) check_message "Azure App Service Deployment Slot ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az resource show --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure App Service Deployment Slot ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure App Service Deployment Slot ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "virtualNetworkSubnetId" ]; then fix_message "az webapp vnet-integration add --resource-group --name --vnet --subnet " fi if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" ${set_name} \"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; esac ;; *) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" --set \"${set_name}\"=\"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure App Service Deployment Slot ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "virtualNetworkSubnetId" ]; then fix_message "az webapp vnet-integration add --resource-group --name --vnet --subnet " fi if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" ${set_name} \"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; esac ;; *) case "${resource_type}" in "Microsoft.Web/sites") fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --namespace \"${namespace_name}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}/slots/${slot_name}\" --set \"${set_name}\"=\"${set_value}\"" ;; "auth") fix_message "az webapp ${resource_type} update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; "identity") fix_message "az webapp ${resource_type} assign --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; *) fix_message "az webapp update --name \"${app_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac ;; esac fi else inc_secure "Azure App Service App ${description} for app \"${app_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${set_value}\"" fi fi } ================================================ FILE: functions/azure/compute/webapp/check_azure_app_service_plan_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_app_service_plan_value # # Check Azure App Service Plan value # # This requires the Azure CLI to be installed and configured #. check_azure_app_service_plan_value () { plan_id="${1}" resource_group="${2}" query_string="${3}" function="${4}" correct_value="${5}" set_name="${7}" set_value="${8}" print_function "check_azure_app_service_plan_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi plan_name=$( basename "${plan_id}" ) check_message "Azure App Service Plan \"${plan_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az appservice plan show --id \"${plan_id}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure App Service Plan \"${plan_name}\" with resource group \"${resource_group}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure App Service Plan \"${plan_name}\" with resource group \"${resource_group}\" is \"${actual_value}\" and not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az appservice plan update --name \"${plan_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az appservice plan update --name \"${plan_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac fi fi else if [ "${actual_value}" != "${correct_value}" ]; then inc_secure "Azure App Service Plan \"${plan_name}\" with resource group \"${resource_group}\" is not \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure App Service Plan \"${plan_name}\" with resource group \"${resource_group}\" is \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az appservice plan update --name \"${plan_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az appservice plan update --name \"${plan_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac fi fi fi } ================================================ FILE: functions/azure/database/check_azure_cosmos_db_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_cosmos_db_value # # Check Azure Cosmos DB value # # This requires the Azure CLI to be installed and configured #. check_azure_cosmos_db_value () { description="${1}" cosmosdb_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" set_name="${7}" set_value="${8}" print_function "check_azure_cosmos_db_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi check_message "${description} for Cosmos DB \"${cosmosdb_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az cosmosdb show --name \"${cosmosdb_name}\" --resource-group \"${resource_group}\" --query \"[].${query_string}\" --output tsv" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Cosmos DB \"${cosmosdb_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Cosmos DB \"${cosmosdb_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az cosmosdb update --name \"${cosmosdb_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az cosmosdb update --name \"${cosmosdb_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"" "fix" ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "${description} for Cosmos DB \"${cosmosdb_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az cosmosdb update --name \"${cosmosdb_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az cosmosdb update --name \"${cosmosdb_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"" ;; esac fi else inc_secure "${description} for Cosmos DB \"${cosmosdb_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/database/check_azure_mysql_db_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_mysql_db_value # # Check Azure MySQL DB value # # This requires the Azure CLI to be installed and configured #. check_azure_mysql_db_value () { description="${1}" server_type="${2}" server_name="${3}" resource_group="${4}" db_name="${5}" query_string="${6}" function="${7}" correct_value="${8}" set_name="${9}" set_value="${10}" print_function "check_azure_mysql_db_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi if [ "${server_type}" = "server" ]; then header_string="${description} for MySQL ${server_type} DB Server \"${server_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\"" check_message "${header_string} is \"${function}\" to \"${correct_value}\"" command="az mysql ${server_type} show --name \"${server_name}\" --resource-group \"${resource_group}\" --query \"[].${query_string}\" --output tsv" command_message "${command}" else header_string="${description} for MySQL ${server_type} DB \"${server_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\"" check_message "${header_string} is \"${function}\" to \"${correct_value}\"" command="az mysql ${server_type} show --server-name \"${server_name}\" --resource-group \"${resource_group}\" --database-name \"${db_name}\" --query \"[].${query_string}\" --output tsv" command_message "${command}" fi actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${header_string} is \"${function}\" to \"${correct_value}\"" else inc_insecure "${header_string} is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az mysql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az mysql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"" ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "${header_string} is \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az mysql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az mysql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"" ;; esac fi else inc_secure "${header_string} is not \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/database/check_azure_postgresql_db_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_postgresql_db_value # # Check Azure PostgreSQL DB value # # This requires the Azure CLI to be installed and configured #. check_azure_postgresql_db_value () { description="${1}" server_type="${2}" server_name="${3}" resource_group="${4}" db_name="${5}" query_string="${6}" function="${7}" correct_value="${8}" set_name="${9}" set_value="${10}" print_function "check_azure_postgresql_db_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi if [ "${server_type}" = "server" ]; then header_string="${description} for PostgreSQL ${server_type} DB Server \"${server_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\"" check_message "${header_string} is \"${function}\" to \"${correct_value}\"" command="az postgresql ${server_type} show --name \"${server_name}\" --resource-group \"${resource_group}\" --query \"[].${query_string}\" --output tsv" command_message "${command}" else header_string="${description} for PostgreSQL ${server_type} DB \"${server_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\"" check_message "${header_string} is \"${function}\" to \"${correct_value}\"" command="az postgresql ${server_type} show --server-name \"${server_name}\" --resource-group \"${resource_group}\" --database-name \"${db_name}\" --query \"[].${query_string}\" --output tsv" command_message "${command}" fi actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${header_string} is \"${function}\" to \"${correct_value}\"" else inc_insecure "${header_string} is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az postgresql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az postgresql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"\"" ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "${header_string} is \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az postgresql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az postgresql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"\"" ;; esac fi else inc_secure "${header_string} is not \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/database/check_azure_redis_cache_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_redis_cache_value # # Check Azure Redis Cache value # # This requires the Azure CLI to be installed and configured #. check_azure_redis_cache_value () { description="${1}" redis_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" set_name="${7}" print_function "check_azure_redis_cache_value" check_message "${description} for Redis Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az redis show --name \"${redis_name}\" --resource-group \"${resource_group}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Redis Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Redis Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az redis update --name \"${redis_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az redis update --name \"${redis_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${correct_value}\"" ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "${description} for Redis Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az redis update --name \"${redis_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az redis update --name \"${redis_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${correct_value}\"" ;; esac fi else inc_secure "${description} for Redis Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/database/check_azure_redis_enterprise_cache_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_redis_enterprise_cache_value # # Check Azure Redis Enterprise Cache value # # This requires the Azure CLI to be installed and configured #. check_azure_redis_enterprise_cache_value () { description="${1}" redis_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" set_name="${7}" print_function "check_azure_redis_enterprise_cache_value" check_message "${description} for Redis Enterprise Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az redisenterprise show --name \"${redis_name}\" --resource-group \"${resource_group}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Redis Enterprise Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Redis Enterprise Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az redisenterprise update --name \"${redis_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az redisenterprise update --name \"${redis_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${correct_value}\"" ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "${description} for Redis Enterprise Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az redisenterprise update --name \"${redis_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az redisenterprise update --name \"${redis_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${correct_value}\"" ;; esac fi else inc_secure "${description} for Redis Enterprise Cache \"${redis_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/database/check_azure_sql_db_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_sql_db_value # # Check Azure SQL DB value # # This requires the Azure CLI to be installed and configured #. check_azure_sql_db_value () { description="${1}" server_type="${2}" server_name="${3}" resource_group="${4}" db_name="${5}" query_string="${6}" function="${7}" correct_value="${8}" set_name="${9}" set_value="${10}" print_function "check_azure_sql_db_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi if [ "${server_type}" = "server" ]; then header_string="${description} for SQL ${server_type} DB Server \"${server_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\"" check_message "${header_string} is \"${function}\" to \"${correct_value}\"" command="az sql ${server_type} show --name \"${server_name}\" --resource-group \"${resource_group}\" --query \"[].${query_string}\" --output tsv" command_message "${command}" else header_string="${description} for SQL ${server_type} DB \"${server_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\"" check_message "${header_string} is \"${function}\" to \"${correct_value}\"" command="az sql ${server_type} show --server-name \"${server_name}\" --resource-group \"${resource_group}\" --database-name \"${db_name}\" --query \"[].${query_string}\" --output tsv" command_message "${command}" fi actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${header_string} is \"${function}\" to \"${correct_value}\"" else inc_insecure "${header_string} is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az sql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az sql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"" ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "${header_string} is \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az sql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az sql ${server_type} update --name \"${server_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"" ;; esac fi else inc_secure "${header_string} is not \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/logging/check_azure_activity_log_alert_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_activity_log_alert_value # # Check Azure Activity Log Alert value # # This requires the Azure CLI to be installed and configured #. check_azure_activity_log_alert_value () { description="${1}" subscription_id="${2}" alert_check="${3}" print_function "check_azure_activity_log_alert_value" query_string="[].{Name:name,Enabled:enabled,Condition:condition.allOf,Actions:actions}" check_message "Azure Activity Log Alert for ${description} for subscription \"${subscription_id}\" is \"${alert_check}\"" command="az monitor activity-log alert list --subscription \"${subscription_id}\" --query \"${query_string}\" | grep \"${alert_check}\"" command_message "${command}" alert_check=$( eval "${command}" ) if [ -n "${alert_check}" ]; then inc_secure "Activity Log Alert for ${description} is enabled" else inc_insecure "Activity Log Alert for ${description} is not enabled" fi } ================================================ FILE: functions/azure/logging/check_azure_monitor_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_monitor_value # # Check Azure Monitor value # # This requires the Azure CLI to be installed and configured #. check_azure_monitor_value () { description="${1}" workspace_name="${2}" resource_id="${3}" monitor_property="${4}" parameter_name="${5}" function="${6}" correct_value="${7}" set_name="${8}" print_function "check_azure_monitor_value" if [ "${parameter_name}" = "" ]; then parameter_string="" else parameter_string=" and parameter \"${parameter_name}\"" fi check_message "Azure Monitor value for workspace \"${workspace_name}\" with Resource ID \"${resource_id}\"${parameter_string} is \"${function}\" to \"${correct_value}\"" command="az monitor \"${monitor_property}\" show --name \"${workspace_name}\" --resource-id \"${resource_id}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for workspace \"${workspace_name}\" with Resource ID \"${resource_id}\"${parameter_string} is \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for workspace \"${workspace_name}\" with Resource ID \"${resource_id}\"${parameter_string} is not \"${function}\" to \"${correct_value}\"" if [ ! "${parameter_name}" = "" ]; then fix_message "az monitor log-analytics workspace update --name \"${workspace_name}\" --resource-id \"${resource_id}\" --query \"${parameter_name}\" --output tsv" fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "${description} for workspace \"${workspace_name}\" with Resource ID \"${resource_id}\"${parameter_string} is not \"${function}\" to \"${correct_value}\"" if [ ! "${parameter_name}" = "" ]; then fix_message "az monitor log-analytics workspace update --name \"${workspace_name}\" --resource-id \"${resource_id}\" --query \"${parameter_name}\" --output tsv" fi else inc_secure "${description} for workspace \"${workspace_name}\" with Resource ID \"${resource_id}\"${parameter_string} is \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/logging/check_azure_monitoring_diagnostics_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2030 # shellcheck disable=SC2031 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_monitoring_diagnostics_value # # Check Azure Monitoring Diagnostics value # # This requires the Azure CLI to be installed and configured #. check_azure_monitoring_diagnostics_value () { resource_id="${1}" print_function "check_azure_monitoring_diagnostics_value" check_message "Checking Azure Monitoring Diagnostics for \"${resource_id}\"" command="az monitor diagnostic-settings list --resource \"${resource_id}\" --output tsv" command_message "${command}" stderr=$( { stdout=$( az monitor diagnostic-settings list --resource "${resource_id}" --output tsv ); } 2>&1 ) if [ -n "${stderr}" ]; then stderr=$( echo "${stderr}" | tr "\n" " " | cut -f2 -d: | cut -f3-11 -d" " ) notice_message "${stderr}" else if [ -n "${stdout}" ]; then inc_secure "Resource logging is enabled for ${resource_id}" else inc_insecure "Resource logging is not enabled for ${resource_id}" fi fi } ================================================ FILE: functions/azure/logging/check_azure_network_watcher_flow_log_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_network_watcher_flow_log_value # # Check Azure Network Watcher Flow Log value # # This requires the Azure CLI to be installed and configured #. check_azure_network_watcher_flow_log_value () { location="${1}" flow_log="${2}" query_string="${3}" correct_value="${4}" parameter_name="${5}" print_function "check_azure_network_watcher_flow_log_value" check_message "Azure Network Watcher Flow Log \"${flow_log}\" has \"${query_string}\" set to \"${correct_value}\"" command="az network watcher flow-log show --location \"${location}\" --name \"${flow_log}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Network Watcher Flow Log \"${flow_log}\" has \"${query_string}\" set to \"${correct_value}\"" else inc_insecure "Azure Network Watcher Flow Log \"${flow_log}\" has \"${query_string}\" not set to \"${correct_value}\"" fix_message "az network watcher flow-log update --location \"${location}\" --name \"${flow_log}\" --\"${parameter_name}\" \"${correct_value}\"" fi } ================================================ FILE: functions/azure/logging/check_azure_network_watcher_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_network_watcher_value # # Check Azure Network Watcher value # # This requires the Azure CLI to be installed and configured #. check_azure_network_watcher_value () { watcher_id="${1}" parameter_name="${2}" correct_value="${3}" print_function "check_azure_network_watcher_value" short_id=$( basename "${watcher_id}" ) check_message "Azure Network Watcher ID \"${short_id}\" has \"${parameter_name}\" set to \"${correct_value}\"" command="az network watcher list --query \"[?contains(id,'${watcher_id}')].${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${parameter_name} is set to ${correct_value} for ${short_id}" else inc_insecure "${parameter_name} is not set to ${correct_value} for ${short_id}" fi } ================================================ FILE: functions/azure/logging/check_azure_storage_logging_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_storage_logging_value # # Check Azure Storage Logging value # # This requires the Azure CLI to be installed and configured #. check_azure_storage_logging_value () { description="${1}" storage_account="${2}" service_type="${3}" query_string="${4}" function="${5}" correct_value="${6}" log_value="${7}" print_function "check_azure_storage_logging_value" short_service=$( echo "${service_type}" | cut -c 1 ) check_message "${description} for \"${file_system}\" for Storage Account \"${storage_account}\" has Parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" command="az storage logging show --services ${short_service} --account-name \"${storage_account}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for File System \"${file_system}\" on Storage Account \"${storage_account}\" has \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for File System \"${file_system}\" on Storage Account \"${storage_account}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" if [ ! "${log_value}" = "" ]; then fix_message "az storage logging update --account-name ${storage_account} --services ${short_service} --log ${log_value} --retention ${correct_value}" fi fi elif [ "${function}" = "ne" ]; then if [ "${actual_value}" != "${correct_value}" ]; then inc_secure "${description} for File System \"${file_system}\" on Storage Account \"${storage_account}\" has \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for File System \"${file_system}\" on Storage Account \"${storage_account}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/network/check_azure_network_private_endpoint_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_network_private_endpoint_value # # Check Azure Network Private Endpoint value # # This requires the Azure CLI to be installed and configured #. check_azure_network_private_endpoint_value () { endpoint_id="${1}" query_string="${2}" function="${3}" correct_value="${4}" endpoint_name=$( basename "${endpoint_id}" ) print_function "check_azure_network_private_endpoint_value" check_message "Azure Network Private Endpoint for \"${endpoint_name}\" is \"${function}\" to \"${correct_value}\"" command="az network private-endpoint show --id \"${endpoint_id}\" --query \"${query_string}\" --output tsv" command_message "${command}" actual_value=$( eval "${command}" 2> /dev/null ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Network Private Endpoint for \"${endpoint_name}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Network Private Endpoint for \"${endpoint_name}\" is \"${actual_value}\" and not \"${function}\" to \"${correct_value}\"" fix_message "az network private-endpoint create --resource-group \ " fix_message "--location --name --vnet-name \ " fix_message "--subnet --private-connection-resource-id \ " fix_message "--connection-name --group-id sites" fi else if [ "${function}" = "ne" ]; then if [ "${actual_value}" != "${correct_value}" ]; then inc_secure "Azure Network Private Endpoint for \"${endpoint_name}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Network Private Endpoint for \"${endpoint_name}\" is \"${actual_value}\" and not \"${function}\" to \"${correct_value}\"" fix_message "az network private-endpoint create --resource-group \ " fix_message "--location --name --vnet-name \ " fix_message "--subnet --private-connection-resource-id \ " fix_message "--connection-name --group-id sites" fi fi fi } ================================================ FILE: functions/azure/network/check_azure_public_ip_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_public_ip_value # # Check Azure Public IP value # # 7.7 Ensure that Public IP addresses are Evaluated on a Periodic Basis (Manual) # # Refer to Section(s) 7.7 Page(s) 309-10 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. check_azure_public_ip_value () { resource_id="${1}" parameter_name="${2}" function="${3}" correct_value="${4}" print_function "check_azure_public_ip_value" check_message "Azure Public IP \"${parameter_name}\" is ${function} to \"${correct_value}\"" short_id=$( basename "${resource_id}" ) command="az network public-ip show --id \"${resource_id}\" --query '${parameter_name}' --output tsv" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${parameter_name}" = "ipAddress" ]; then if [ "${correct_value}" = "" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "No Azure Public IP found for \"${short_id}\"" else inc_insecure "Azure Public IP found for \"${short_id}\": \"${actual_value}\"" fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Public IP \"${parameter_name}\" is ${function} to \"${correct_value}\"" else inc_insecure "Azure Public IP \"${parameter_name}\" is not ${function} to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/network/check_azure_vnet_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_vnet_value # # Check Azure VNet value # # This requires the Azure CLI to be installed and configured #. check_azure_vnet_value () { vnet_name="${1}" resource_group="${2}" subnet_name="${3}" parameter_name="${4}" function="${5}" correct_value="${6}" print_function "check_azure_vnet_value" check_message "Azure VNet \"${vnet_name}\" in Resource Group \"${resource_group}\" Subnet \"${subnet_name}\" has \"${parameter_name}\" ${function} to \"${correct_value}\"" command="az network vnet subnet show --name \"${subnet_name}\" --resource-group \"${resource_group}\" --vnet-name \"${vnet_name}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "$command" actual_value=$( eval "$command" ) if [ "${function}" = "ne" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure VNet \"${vnet_name}\" in Resource Group \"${resource_group}\" Subnet \"${subnet_name}\" does not have \"${parameter_name}\" ${function} to \"${correct_value}\"" else inc_secure "Azure VNet \"${vnet_name}\" in Resource Group \"${resource_group}\" Subnet \"${subnet_name}\" has \"${parameter_name}\" ${function} to \"${correct_value}\"" fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure VNet \"${vnet_name}\" in Resource Group \"${resource_group}\" Subnet \"${subnet_name}\" has \"${parameter_name}\" ${function} to \"${correct_value}\"" else inc_insecure "Azure VNet \"${vnet_name}\" in Resource Group \"${resource_group}\" Subnet \"${subnet_name}\" does not have \"${parameter_name}\" ${function} to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/other/audit_azure.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_all # # Audit Azure all # # Run various Azure audit tests # # This requires the Azure CLI to be installed and configured #. audit_azure_all () { print_function "audit_azure_all" audit_azure_survey audit_azure_extensions audit_azure_storage_services audit_azure_compute_services audit_azure_database_services audit_azure_identity_services audit_azure_logging_and_monitoring audit_azure_networking_services audit_azure_security_services } # funct_audit_azure # # Audit Azure #. funct_audit_azure () { audit_mode="${1}" print_function "funct_audit_azure" check_environment check_azure audit_azure_all print_results } ================================================ FILE: functions/azure/security/check_azure_basic_authentication_publishing_credential_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_basic_authentication_publishing_credential_value # # Check Azure Basic Authentication Publishing Credential value # # This requires the Azure CLI to be installed and configured #. check_azure_basic_authentication_publishing_credential_value () { app_name="${1}" resource_group="${2}" resource_name="${3}" resource_type="${4}" name_space="${5}" query_string="${6}" function="${7}" correct_value="${8}" set_name="${9}" set_value="${10}" print_function "check_azure_basic_authentication_publishing_credential_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi check_message "Azure Basic Authentication Publishing Credential for ${resource_name} for app \"${app_name}\" with resource group \"${resource_group}\" and resource \"${resource_name}\" and resource type \"${resource_type}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az resource show --name \"${resource_name}\" --name-space \"${name_space}\" --resource-group \"${resource_group}\" --resource-type \"${resource_type}\" --parent \"sites/${app_name}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Basic Authentication Publishing Credential for ${resource_name} for app \"${app_name}\" with resource group \"${resource_group}\" and resource \"${resource_name}\" and resource type \"${resource_type}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Basic Authentication Publishing Credential for ${resource_name} for app \"${app_name}\" with resource group \"${resource_group}\" and resource \"${resource_name}\" and resource type \"${resource_type}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure Basic Authentication Publishing Credential for ${resource_name} for app \"${app_name}\" with resource group \"${resource_group}\" and resource \"${resource_name}\" and resource type \"${resource_type}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az resource update --name \"${resource_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${set_value}\"" ;; esac fi else inc_secure "Azure Basic Authentication Publishing Credential for ${resource_name} for app \"${app_name}\" with resource group \"${resource_group}\" and resource \"${resource_name}\" and resource type \"${resource_type}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/security/check_azure_lock_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_lock_value # # Check Azure Lock value # # This requires the Azure CLI to be installed and configured # check_azure_lock_value () { lock_name="$1" resource_group="$2" resource_type="$3" query_string="$4" function="$5" correct_value="$6" set_name="$7" print_function "check_azure_lock_value" check_message "Azure Lock Value" command="az lock show --name \"${lock_name}\" --resource-group \"${resource_group}\" --resource-type \"${resource_type}\" --query \"${query_string}\" --output tsv" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Lock \"${lock_name}\" in resource group \"${resource_group}\" resource type \"${resource_type}\" parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Lock \"${lock_name}\" in resource group \"${resource_group}\" resource type \"${resource_type}\" parameter \"${query_string}\" is \"${function}\" to \"${actual_value}\" instead of \"${correct_value}\"" if [ "${set_name}" != "" ]; then case "${set_name}" in *"--"*) fix_message "az lock update --name \"${lock_name}\" --resource-group \"${resource_group}\" --resource-type \"${resource_type}\" --set \"${set_name}\" \"${correct_value}\"" ;; *) fix_message "az lock update --name \"${lock_name}\" --resource-group \"${resource_group}\" --resource-type \"${resource_type}\" \"${set_name}\"=\"${correct_value}\"" ;; esac fi fi } ================================================ FILE: functions/azure/security/check_azure_microsoft_defender_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_microsoft_defender_value # # Check Azure Microsoft Defender value # # This requires the Azure CLI to be installed and configured #. check_azure_microsoft_defender_value () { description="${1}" parameter_name="${2}" correct_value="${3}" correct_status="${4}" resource_type="${5}" print_function "check_azure_microsoft_defender_value" if [ "${resource_type}" = "" ]; then resource_check="ignore" else resource_check=$( az resource list --resource-type "${resource_type}" --output tsv ) fi if [ "${resource_check}" = "" ]; then if [ "${correct_value}" = "Exists" ]; then inc_insecure "Microsoft Defender \"${description}\" does not exist" else verbose_message "Azure Resource Type \"${resource_type}\" not found" fi else if [ "${correct_value}" = "Exists" ]; then inc_secure "Microsoft Defender \"${description}\" exists" else check_message "Azure Microsoft Defender \"${description}\" parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" command="az security pricing show --name \"${parameter_name}\" --query \"pricingTier\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Microsoft Defender \"${description}\" parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Microsoft Defender \"${description}\" parameter \"${parameter_name}\" is not \"${function}\" to \"${correct_value}\"" if [ "${parameter_name}" = "CloudPosture" ]; then fix_message "az security pricing update --name \"${parameter_name}\" --tier \"${correct_value}\" --extensions name=ApiPosture isEnabled=true" else fix_message "az security pricing update --name \"${parameter_name}\" --tier \"${correct_value}\"" fi fi if [ ! "${correct_status}" = "" ]; then check_message "Azure Microsoft Defender \"${description}\" Status is \"${function}\" to \"${correct_status}\"" command="az security pricing show --name \"${parameter_name}\" --query \"[operationStatus]\" --output tsv 2> /dev/null" command_message "${command}" actual_status=$( eval "${command}" ) if [ "${actual_status}" = "${correct_status}" ]; then inc_secure "Microsoft Defender \"${description}\" Status is \"${function}\" to \"${correct_status}\"" else inc_insecure "Microsoft Defender \"${description}\" Status is not \"${function}\" to \"${correct_status}\"" fi fi fi fi } ================================================ FILE: functions/azure/security/check_azure_network_security_perimeter_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_network_security_perimeter_value # # Check Azure Network Security Perimeter value # # This requires the Azure CLI to be installed and configured #. check_azure_network_security_perimeter_value () { nsp_name="${1}" group_name="${2}" policy_name="${3}" query_string="${4}" function="${5}" correct_value="${6}" print_function "check_azure_network_security_perimeter_value" if [ "${policy_name}" = "association" ]; then check_message "Azure Network Security Perimeter \"${nsp_name}\" is associated with \"${correct_value}\"" command="az network perimeter association list --perimeter-name \"${nsp_name}\" --resource-group \"${group_name}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Network Security Perimeter \"${nsp_name}\" is associated with \"${correct_value}\"" else inc_insecure "Azure Network Security Perimeter \"${nsp_name}\" is not associated with \"${correct_value}\"" fix_message "az network perimeter association create --perimeter-name --resource-group --association-name --target-resource-id " fi fi } ================================================ FILE: functions/azure/security/check_azure_nsg_security_rule_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_nsg_security_rule_value # # Check Azure NSG Security Rule value # # This requires the Azure CLI to be installed and configured #. check_azure_nsg_security_rule_value () { description="${1}" rule_id="${2}" direction="${3}" parameter_name="${4}" function="${5}" correct_value="${6}" print_function "check_azure_nsg_security_rule_value" short_id=$( basename "${rule_id}" ) check_message "NSG Rule ID \"${short_id}\" is \"${direction}\"" command="az network nsg rule show --id ${rule_id} --query \"direction\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${direction}" ]; then check_message "${description} rule ID \"${short_id}\" parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" if [ "${function}" = "ne" ]; then command="az network nsg rule show --id ${rule_id} --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ] || [ "${actual_value}" = "*" ] || [ "${actual_value}" = "" ]; then inc_insecure "${description} \"${short_id}\" parameter \"${parameter_name}\" is not \"${function}\" to \"${correct_value}\" or \"*\" or \"\"" else inc_secure "${description} \"${short_id}\" parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" fi fi else notice_message "NSG Rule ID \"${short_id}\" is not \"${direction}\"" fi } ================================================ FILE: functions/azure/security/check_azure_resource_manager_lock.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_resource_manager_lock # # Check Azure Resource Manager Lock # # This requires the Azure CLI to be installed and configured #. check_azure_resource_manager_lock () { description="${1}" storage_account="${2}" resource_group="${3}" parameter_name="${4}" function="${5}" correct_value="${6}" resource_type="${7}" print_function "check_azure_resource_manager_lock" check_message "${description} for Storage Account \"${storage_account}\" with resource group \"${resource_group}\" and resource type \"${resource_type}\" had a \"${correct_value}\" lock applied" command="az resource lock list --resource-group \"${resource_group}\" --resource-type \"${resource_type}\" --resource-name \"${storage_account}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Storage Account \"${storage_account}\" with resource group \"${resource_group}\" and resource type \"${resource_type}\" has a \"${correct_value}\" lock applied" else inc_insecure "Storage Account \"${storage_account}\" with resource group \"${resource_group}\" and resource type \"${resource_type}\" does not have a \"${correct_value}\" lock applied" fix_message "az lock create --name ${correct_value} --resource-group ${resource_group} --resource-name ${storage_account} --resource-type ${resource_type} --lock-type ${correct_value}" fi } ================================================ FILE: functions/azure/security/check_azure_security_contact_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_security_contact_value # # Check Azure Security Contact value # # Refer to https://learn.microsoft.com/en-us/cli/azure/security/contact?view=azure-cli-latest # # This requires the Azure CLI to be installed and configured #. check_azure_security_contact_value () { contact_name="${1}" parameter_name="${2}" function="${3}" correct_value="${4}" print_function "check_azure_security_contact_value" check_message "Azure Security Contact \"${contact_name}\" Parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" command="az security contact show --name \"${contact_name}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Security Contact \"${contact_name}\" Parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Security Contact \"${contact_name}\" Parameter \"${parameter_name}\" is not \"${function}\" to \"${correct_value}\"" fix_message "az security contact update --name ${contact_name} --email --notifications-by-role '{\"state\":\"On\",\"roles\":[\"Owner\"]}' --alert-notifications '{\"state\":\"On\",\"minimalSeverity\":\"Low\"}'" fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Security Contact \"${contact_name}\" Parameter \"${parameter_name}\" is not \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Security Contact \"${contact_name}\" Parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" fix_message "az security contact update --name ${contact_name} --email --notifications-by-role '{\"state\":\"On\",\"roles\":[\"Owner\"]}' --alert-notifications '{\"state\":\"On\",\"minimalSeverity\":\"Low\"}'" fi fi } ================================================ FILE: functions/azure/security/check_azure_security_setting.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_security_setting_value # # Check Azure Security Setting value # # This requires the Azure CLI to be installed and configured #. check_azure_security_setting_value () { description="${1}" setting_name="${2}" parameter_name="${3}" correct_value="${4}" print_function "check_azure_security_setting_value" check_message "${description} \"${setting_name}\" parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" command="az security setting show --name \"${setting_name}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} \"${setting_name}\" parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} \"${setting_name}\" parameter \"${parameter_name}\" is not \"${function}\" to \"${correct_value}\"" fi } ================================================ FILE: functions/azure/security/check_azure_waf_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_waf_value # # Check Azure WAF value # # This requires the Azure CLI to be installed and configured #. check_azure_waf_value () { waf_name="${1}" policy_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" parameter_name="${7}" parameter_value="${8}" waf_id="${waf_name}" print_function "check_azure_waf_value" if [ "${policy_name}" = "waf-policy" ]; then check_message "Azure WAF \"${waf_id}\" has \"${query_string}\" ${function} to \"${correct_value}\"" if [ "${query_string}" = "managedRules.managedRuleSets" ]; then command="az network application-gateway ${policy_name} show --id \"${waf_id}\" --query \"${query_string}\" | grep \"${correct_value}\" | cut -f4 -d\\\" 2> /dev/null" else command="az network application-gateway ${policy_name} show --id \"${waf_id}\" --query \"${query_string}\" --output tsv 2> /dev/null" fi command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "ne" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure WAF \"${waf_id}\" does not have \"${query_string}\" ${function} to \"${correct_value}\"" else inc_secure "Azure WAF \"${waf_id}\" has \"${query_string}\" ${function} to \"${correct_value}\"" fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure WAF \"${waf_id}\" has \"${query_string}\" ${function} to \"${correct_value}\"" else inc_insecure "Azure WAF \"${waf_id}\" does not have \"${query_string}\" ${function} to \"${correct_value}\"" if [ "${parameter_name}" != "" ]; then case "${parameter_name}" in "--"*) fix_message "az network application-gateway ${policy_name} update --id \"${waf_id}\" \"${parameter_name}\" \"${parameter_value}\"" ;; *) fix_message "az network application-gateway ${policy_name} update --id \"${waf_id}\" --set \"${parameter_name}\"=\"\"${parameter_value}\"" ;; esac fi fi fi else if [ "${policy_name}" = "" ]; then policy_string="" check_message "Azure WAF \"${waf_name}\" in Resource Group \"${resource_group}\" has \"${query_string}\" ${function} to \"${correct_value}\"" command="az network application-gateway show --name \"${waf_name}\" --resource-group \"${resource_group}\" --query \"${query_string}\" --output tsv 2> /dev/null" else policy_string=" Policy \"${policy_name}\"" check_message "Azure WAF Policy \"${policy_name}\" in Resource Group \"${resource_group}\" has \"${query_string}\" ${function} to \"${correct_value}\"" command="az network application-gateway ${policy_name} show --name \"${waf_name}\" --resource-group \"${resource_group}\" --query \"${query_string}\" --output tsv 2> /dev/null" fi command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "ne" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure WAF \"${waf_name}\"${policy_string} in Resource Group \"${resource_group}\" does not have \"${query_string}\" ${function} to \"${correct_value}\"" else inc_secure "Azure WAF \"${waf_name}\"${policy_string} in Resource Group \"${resource_group}\" has \"${query_string}\" ${function} to \"${correct_value}\"" fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure WAF \"${waf_name}\"${policy_string} in Resource Group \"${resource_group}\" has \"${query_string}\" ${function} to \"${correct_value}\"" else inc_insecure "Azure WAF \"${waf_name}\"${policy_string} in Resource Group \"${resource_group}\" does not have \"${query_string}\" ${function} to \"${correct_value}\"" if [ "${parameter_name}" != "" ]; then case "${parameter_name}" in "--"*) fix_message "az network application-gateway ${policy_name} update --name \"${waf_name}\" --resource-group \"${resource_group}\" \"${parameter_name}\" \"${parameter_value}\"" ;; *) fix_message "az network application-gateway ${policy_name} update --name \"${waf_name}\" --resource-group \"${resource_group}\" --set \"${parameter_name}\"=\"${parameter_value}\"" ;; esac fi fi fi fi } ================================================ FILE: functions/azure/storage/check_azure_backup_policy_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_backup_policy_value # # Check Azure Backup policy value # # This requires the Azure CLI to be installed and configured #. check_azure_backup_policy_value () { description="${1}" policy_name="${2}" vault_name="${3}" resource_group="${4}" query_string="${5}" function="${6}" correct_value="${7}" set_name="${8}" set_value="${9}" print_function "check_azure_backup_policy_value" check_message "Azure Backup Policy ${description} for policy \"${policy_name}\" with vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az backup policy show --name \"${policy_name}\" --vault-name \"${vault_name}\" --resource-group \"${resource_group}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Backup Policy ${description} for policy \"${policy_name}\" with vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Backup Policy ${description} for policy \"${policy_name}\" with vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az backup policy update --name \"${policy_name}\" --vault-name \"${vault_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az backup policy update --name \"${policy_name}\" --vault-name \"${vault_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${correct_value}\"" ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure Backup Policy ${description} for policy \"${policy_name}\" with vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az backup policy update --name \"${policy_name}\" --vault-name \"${vault_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az backup policy update --name \"${policy_name}\" --vault-name \"${vault_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${correct_value}\"" ;; esac fi else inc_secure "Azure Backup Policy ${description} for policy \"${policy_name}\" with vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/storage/check_azure_data_factory_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_data_factory_value # # Check Azure Data Factory value # # This requires the Azure CLI to be installed and configured #. check_azure_data_factory_value () { description="${1}" data_factory_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" set_name="${7}" set_value="${8}" print_function "check_azure_data_factory_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi check_message "${description} for Data Factory \"${data_factory_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az datafactory show --name \"${data_factory_name}\" --resource-group \"${resource_group}\" --query \"[].${query_string}\" --output tsv" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Data Factory \"${data_factory_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Data Factory \"${data_factory_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az datafactory update --name \"${data_factory_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az datafactory update --name \"${data_factory_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"" ;; esac fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "${description} for Data Factory \"${data_factory_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az datafactory update --name \"${data_factory_name}\" --resource-group \"${resource_group}\" ${set_name} \"${set_value}\"" ;; *) fix_message "az datafactory update --name \"${data_factory_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"\"${set_value}\"" ;; esac fi else inc_secure "${description} for Data Factory \"${data_factory_name}\" with Resource Group \"${resource_group}\" Parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/storage/check_azure_databox_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_databox_value # # Check Azure Databox value # # This requires the Azure CLI to be installed and configured #. check_azure_databox_value () { description="${1}" job_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" set_name="${7}" print_function "check_azure_databox_value" check_message "${description} for Databox job \"${job_name}\" in resource group \"${resource_group}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" command="az databox job show --name ${job_name} --resource-group ${resource_group} --query '${query_string}' --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then secure_message "${description} for Databox job \"${job_name}\" in resource group \"${resource_group}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" else insecure_message "${description} for Databox job \"${job_name}\" in resource group \"${resource_group}\" has parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az databox job update --name \"${job_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az databox job update --name \"${job_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${correct_value}\"" ;; esac fi fi } ================================================ FILE: functions/azure/storage/check_azure_databricks_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_databricks_value # # Check Azure Databricks value # # This requires the Azure CLI to be installed and configured #. check_azure_databricks_value () { description="${1}" workspace_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" parameter_name="${7}" print_function "check_azure_databricks_value" check_message "Azure Databricks ${description} for workspace \"${workspace_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az databricks workspace show --name \"${workspace_name}\" --resource-group \"${resource_group}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for workspace \"${workspace_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for workspace \"${workspace_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${parameter_name}" = "" ]; then fix_message "az databricks workspace update --name \"${workspace_name}\" --resource-group \"${resource_group}\" --query \"${parameter_name}\" --output tsv" fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "${description} for workspace \"${workspace_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${parameter_name}" = "" ]; then fix_message "az databricks workspace update --name \"${workspace_name}\" --resource-group \"${resource_group}\" --query \"${parameter_name}\" --output tsv" fi else inc_secure "${description} for workspace \"${workspace_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/storage/check_azure_elastic_san_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_elastic_san_value # # Check Azure Elastic SAN value # # This requires the Azure CLI to be installed and configured #. check_azure_elastic_san_value () { description="${1}" elastic_san_id="${2}" elastic_san_name="${3}" resource_group="${4}" volume_group_name="${5}" query_string="${6}" function="${7}" correct_value="${8}" set_name="${9}" set_value="${10}" print_function "check_azure_elastic_san_value" if [ "${set_value}" = "" ]; then set_value="${correct_value}" fi if [ "${volume_group_name}" = "" ]; then short_name=$( basename "${elastic_san_id}" ) check_message "${description} for Elastic SAN \"${short_name}\" has Parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" command="az elastic-san show --id \"${elastic_san_id}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Elastic SAN \"${short_name}\" has \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Elastic SAN \"${short_name}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" if [ "${set_name}" != "" ]; then command="az elastic-san update --id \"${elastic_san_id}\" ${set_name} \"${set_value}\"" fix_message "${command}" fi fi else if [ "${function}" = "ne" ]; then if [ "${actual_value}" != "${correct_value}" ]; then inc_secure "${description} for Elastic SAN \"${short_name}\" has \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Elastic SAN \"${short_name}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" if [ "${set_name}" != "" ]; then command="az elastic-san update --id \"${elastic_san_id}\" ${set_name} \"${set_value}\"" fix_message "${command}" fi fi fi fi else command="az elastic-san volume-group show --resource-group \"${resource_group}\" --elastic-san \"${elastic_san_name}\" --name \"${volume_group_name}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Elastic SAN \"${elastic_san_name}\" Volume Group \"${volume_group_name}\" has Parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Elastic SAN \"${elastic_san_name}\" Volume Group \"${volume_group_name}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" if [ "${set_name}" != "" ]; then command="az elastic-san volume-group update --resource-group \"${resource_group}\" --elastic-san \"${elastic_san_name}\" --name \"${volume_group_name}\" ${set_name} \"${set_value}\"" fix_message "${command}" fi fi else if [ "${function}" = "ne" ]; then if [ "${actual_value}" != "${correct_value}" ]; then inc_secure "${description} for Elastic SAN \"${elastic_san_name}\" Volume Group \"${volume_group_name}\" has \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Elastic SAN \"${elastic_san_name}\" Volume Group \"${volume_group_name}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" if [ "${set_name}" != "" ]; then command="az elastic-san volume-group update --resource-group \"${resource_group}\" --elastic-san \"${elastic_san_name}\" --name \"${volume_group_name}\" ${set_name} \"${set_value}\"" fix_message "${command}" fi fi fi fi fi } ================================================ FILE: functions/azure/storage/check_azure_file_share_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_file_share_value # # Check Azure File Share value # # This requires the Azure CLI to be installed and configured #. check_azure_file_share_value () { description="${1}" storage_account="${2}" resource_group="${3}" share_propery="${4}" parameter_name="${5}" function="${6}" correct_value="${7}" set_name="${8}" retention_days="${9}" print_function "check_azure_file_share_value" check_message "${description} for Shares on Storage Account \"${storage_account}\" is \"${function}\" to \"${correct_value}\"" command="az storage account file-${share_propery} show --account-name \"${storage_account}\" --resource-group \"${resource_group}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Shares for Storage Account \"${storage_account}\" has ${description} \"${function}\" to \"${correct_value}\"" else inc_insecure "Shares for Storage Account \"${storage_account}\" does not have ${description} \"${function}\" to \"${correct_value}\"" if [ ! -z "${set_name}" ]; then case "${set_name}" in "--"*) if [ "${retention_days}" = "" ]; then fix_message "az storage account file-${share_propery} update --name ${storage_account} --resource-group ${resource_group} ${set_name} ${correct_value}" else fix_message "az storage account file-${share_propery} update --name ${storage_account} --resource-group ${resource_group} ${set_name} ${correct_value} --retention-days ${retention_days}" fi ;; *) fix_message "az storage account file-${share_propery} update --name ${storage_account} --resource-group ${resource_group} --set ${set_name}=${correct_value}" ;; esac fi fi } ================================================ FILE: functions/azure/storage/check_azure_netapp_file_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_netapp_file_value # # Check Azure NetApp File value # # This requires the Azure CLI to be installed and configured #. check_azure_netapp_file_value () { description="${1}" storage_account="${2}" resource_group="${3}" parameter_name="${4}" function="${5}" correct_value="${6}" print_function "check_azure_netapp_file_value" check_message "${description} for Shares on Storage Account \"${storage_account}\" is \"${function}\" to \"${correct_value}\"" command="az netappfiles account show --account-name \"${storage_account}\" --resource-group \"${resource_group}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Shares for Storage Account \"${storage_account}\" has ${description} \"${function}\" to \"${correct_value}\"" else inc_insecure "Shares for Storage Account \"${storage_account}\" does not have ${description} \"${function}\" to \"${correct_value}\"" if [ "${parameter_name}" = "encryptionKeySource" ]; then fix_message "az keyvault set-policy --name --object-id --key-permissions get wrapKey unwrapKey" fix_message "az netappfiles account encryption-key-source update --resource-group --account-name --encryption-key-source Microsoft.KeyVault --key-vault-key-uri " else if [ ! -z "${set_name}" ]; then case "${set_name}" in "--"*) if [ "${retention_days}" = "" ]; then fix_message "az netappfiles account update --name ${storage_account} --resource-group ${resource_group} ${set_name} ${correct_value}" else fix_message "az netappfiles account update --name ${storage_account} --resource-group ${resource_group} ${set_name} ${correct_value} --retention-days ${retention_days}" fi ;; *) fix_message "az netappfiles account update --name ${storage_account} --resource-group ${resource_group} --set ${set_name}=${correct_value}" ;; esac fi fi fi } ================================================ FILE: functions/azure/storage/check_azure_storage_account_container_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_storage_account_container_value # # Check Azure Storage Account Container value # # This requires the Azure CLI to be installed and configured #. check_azure_storage_account_container_value () { description="${1}" storage_account="${2}" resource_group="${3}" container_property="${4}" parameter_name="${5}" function="${6}" correct_value="${7}" set_name="${8}" print_function "check_azure_storage_account_container_value" if [ "${resource_group}" = "" ]; then check_message "${description} for Storage Containers on Storage Account \"${storage_account}\" is \"${correct_value}\"" command="az storage account blob-${container_property} show --account-name \"${storage_account}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) else check_message "${description} for Storage Containers on Storage Account \"${storage_account}\" Resource Group \"${resource_group}\" is \"${correct_value}\"" command="az storage account blob-${container_property} show --account-name \"${storage_account}\" --resource-group \"${resource_group}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) fi if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Storage Containers on Storage Account \"${storage_account}\" has ${description} \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Storage Containers on Storage Account \"${storage_account}\" does not have ${description} \"${function}\" to \"${correct_value}\"" if [ ! -z "${set_name}" ]; then if [ "${resource_group}" = "" ]; then case "${set_name}" in "--"*) fix_message "az storage account blob-${container_property} update --account-name ${storage_account} ${set_name} ${correct_value}" ;; *) fix_message "az storage account blob-${container_property} update --account-name ${storage_account} --set ${set_name}=${correct_value}" ;; esac else case "${set_name}" in "--"*) fix_message "az storage account blob-${container_property} update --account-name ${storage_account} --resource-group ${resource_group} ${set_name} ${correct_value}" ;; *) fix_message "az storage account blob-${container_property} update --account-name ${storage_account} --resource-group ${resource_group} --set ${set_name}=${correct_value}" ;; esac fi fi fi } ================================================ FILE: functions/azure/storage/check_azure_storage_account_keys_rotation.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2086 # shellcheck disable=SC2154 # check_azure_storage_account_keys_rotation # # Check Azure Storage Account Keys Rotation # # This requires the Azure CLI to be installed and configured #. check_azure_storage_account_keys_rotation () { storage_account="${1}" resource_id="${2}" correct_value="${3}" print_function "check_azure_storage_account_keys_rotation" check_message "Storage Account \"${storage_account}\" has access keys regenerated in the last \"${correct_value}\" days" command="az monitor activity-log list --namespace Microsoft.Storage --offset ${correct_value}d --query \"[?contains(authorization.action, 'regenerateKey')]\" --resource-id \"${resource_id}\" 2> /dev/null |grep \"Succeeded\"" command_message "${command}" status_check=$( eval "${command}" ) if [ -n "${status_check}" ]; then inc_secure "Storage Account \"${storage_account}\" has access keys regenerated in the last \"${correct_value}\" days" else creation_date=$( az storage account show --name "${storage_account}" --query "creationTime" --output tsv | cut -d T -f 1 ) if [ "${os_name}" = "Linux" ]; then creation_secs=$( date -d "${creation_date}" +%s ) current_secs=$( date +%s ) else if [ "${os_name}" = "Darwin" ]; then creation_secs=$( date -j -f "%Y-%m-%d" "${creation_date}" +%s ) current_secs=$( date +%s ) fi fi diff_secs=$(( current_secs - creation_secs )) diff_days=$(( diff_secs / 86400 )) if [ ${diff_days} -le ${correct_value} ]; then inc_secure "Storage Account \"${storage_account}\" has access keys generated in the last \"${correct_value}\" days" else inc_insecure "Storage Account \"${storage_account}\" does not have access keys regenerated in the last \"${correct_value}\" days" fi fi } ================================================ FILE: functions/azure/storage/check_azure_storage_account_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_storage_account_value # # Check Azure Storage Account value # # This requires the Azure CLI to be installed and configured #. check_azure_storage_account_value () { description="${1}" storage_account="${2}" resource_group="${3}" parameter_name="${4}" function="${5}" correct_value="${6}" set_name="${7}" print_function "check_azure_storage_account_value" if [ "${resource_group}" = "" ]; then check_message "${description} for Storage Account \"${storage_account}\" is \"${correct_value}\"" command="az storage account show --name \"${storage_account}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Storage Account \"${storage_account}\" has ${description} \"${function}\" to \"${correct_value}\"" else inc_insecure "Storage Account \"${storage_account}\" does not have ${description} \"${function}\" to \"${correct_value}\"" if [ ! -z "${set_name}" ]; then case "${set_name}" in "--"*) fix_message "az storage account update --name ${storage_account} ${set_name} ${correct_value}" ;; *) fix_message "az storage account update --name ${storage_account} --set ${set_name}=${correct_value}" ;; esac fi fi else if [ "${function}" = "ne" ]; then if [ "${actual_value}" != "${correct_value}" ]; then inc_secure "Storage Account \"${storage_account}\" does not have ${description} \"${function}\" to \"${correct_value}\"" else inc_insecure "Storage Account \"${storage_account}\" has ${description} \"${function}\" to \"${correct_value}\"" if [ ! -z "${set_name}" ]; then case "${set_name}" in "--"*) fix_message "az storage account update --name ${storage_account} ${set_name} ${correct_value}" ;; *) fix_message "az storage account update --name ${storage_account} --set ${set_name}=${correct_value}" ;; esac fi fi fi fi else command="az storage account show --name \"${storage_account}\" --query \"resourceGroup\" --output tsv 2> /dev/null" command_message "${command}" resource_group=$( eval "${command}" ) check_message "${description} for Storage Account \"${storage_account}\" Resource Group \"${resource_group}\" is \"${correct_value}\"" command="az storage account show --name \"${storage_account}\" --resource-group \"${resource_group}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Storage Account \"${storage_account}\" has ${description} \"${function}\" to \"${correct_value}\" for resource group \"${resource_group}\"" else inc_insecure "Storage Account \"${storage_account}\" does not have ${description} \"${function}\" to \"${correct_value}\" for resource group \"${resource_group}\"" if [ ! -z "${set_name}" ]; then case "${set_name}" in "--"*) fix_message "az storage account update --name ${storage_account} --resource-group ${resource_group} ${set_name} ${correct_value}" ;; *) fix_message "az storage account update --name ${storage_account} --resource-group ${resource_group} --set ${set_name}=${correct_value}" ;; esac fi fi else if [ "${function}" = "ne" ]; then if [ "${actual_value}" != "${correct_value}" ]; then inc_secure "Storage Account \"${storage_account}\" does not have ${description} \"${function}\" to \"${correct_value}\" for resource group \"${resource_group}\"" else inc_insecure "Storage Account \"${storage_account}\" has ${description} \"${function}\" to \"${correct_value}\" for resource group \"${resource_group}\"" if [ ! -z "${set_name}" ]; then case "${set_name}" in "--"*) fix_message "az storage account update --name ${storage_account} --resource-group ${resource_group} ${set_name} ${correct_value}" ;; *) fix_message "az storage account update --name ${storage_account} --resource-group ${resource_group} --set ${set_name}=${correct_value}" ;; esac fi fi fi fi fi } ================================================ FILE: functions/azure/storage/check_azure_storage_blob_policy_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_storage_blob_policy_value # # Check Azure Storage Blob Policy value # # This requires the Azure CLI to be installed and configured #. check_azure_storage_blob_policy_value () { description="${1}" storage_account="${2}" blob_property="${5}" blob_policy="${6}" parameter_name="${5}" function="${6}" correct_value="${7}" set_name="${8}" print_function "check_azure_storage_blob_policy_value" check_message "${description} for Storage Blobs Property \"${blob_property}\" Policy \"${blob_policy}\" on account \"${storage_account}\" is \"${function}\" to \"${correct_value}\"" if [ "${azure_auth_mode}" = "login" ]; then command="az storage blob ${blob_property} ${blob_policy} show --account-name \"${storage_account}\" --query \"${parameter_name}\" --output tsv --auth-mode \"${azure_auth_mode}\" 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) else command="az storage blob ${blob_property} ${blob_policy} show --account-name \"${storage_account}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) fi if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Storage Blobs Property \"${blob_property}\" Policy \"${blob_policy}\" on account \"${storage_account}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Storage Blobs Property \"${blob_property}\" Policy \"${blob_policy}\" on account \"${storage_account}\" is not \"${function}\" to \"${correct_value}\"" if [ ! -z "${set_name}" ]; then case "${set_name}" in "--"*) fix_message "az storage blob ${blob_property} ${blob_policy} update --name ${storage_account} ${set_name} ${correct_value}" ;; *) fix_message "az storage blob ${blob_property} ${blob_policy} update --name ${storage_account} --set ${set_name}=${correct_value}" ;; esac fi fi } ================================================ FILE: functions/azure/storage/check_azure_storage_blob_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_storage_blob_value # # Check Azure Storage Blob value # # This requires the Azure CLI to be installed and configured #. check_azure_storage_blob_value () { description="${1}" storage_account="${2}" container_name="${3}" blob_name="${4}" parameter_name="${5}" function="${6}" correct_value="${7}" set_name="${8}" print_function "check_azure_storage_account_value" check_message "${description} for Storage Blob \"${blob_name}\" on account \"${storage_account}\" in container \"${container_name}\" is \"${function} to \"${correct_value}\"" if [ "${azure_auth_mode}" = "login" ]; then command="az storage blob ${blob_property} ${blob_policy} show --account-name \"${storage_account}\" --query \"${parameter_name}\" --output tsv --auth-mode \"${azure_auth_mode}\" 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) else command="az storage blob ${blob_property} ${blob_policy} show --account-name \"${storage_account}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) fi if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Storage Blob \"${blob_name}\" on account \"${storage_account}\" in container \"${container_name}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Storage Blob \"${blob_name}\" on account \"${storage_account}\" in container \"${container_name}\" is not \"${function}\" to \"${correct_value}\"" if [ ! -z "${set_name}" ]; then case "${set_name}" in "--"*) fix_message "az storage blob ${blob_property} ${blob_policy} update --name ${storage_account} ${set_name} ${correct_value}" ;; *) fix_message "az storage blob ${blob_property} ${blob_policy} update --name ${storage_account} --set ${set_name}=${correct_value}" ;; esac fi fi } ================================================ FILE: functions/azure/storage/check_azure_storage_container_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_storage_container_value # # Check Azure Storage Container value # # This requires the Azure CLI to be installed and configured #. check_azure_storage_container_value () { description="${1}" storage_account="${2}" container_name="${3}" query_string="${4}" function="${5}" correct_value="${6}" print_function "check_azure_storage_container_value" check_message "${description} for Storage Container \"${container_name}\" for Storage Account \"${storage_account}\" has Parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" command="az storage container show --account-name \"${storage_account}\" --name \"${container_name}\" --query \"${query_string}\" --auth-mode \"${azure_auth_mode}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for Storage Container \"${container_name}\" on Storage Account \"${storage_account}\" has \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Storage Container \"${container_name}\" on Storage Account \"${storage_account}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" fi elif [ "${function}" = "ne" ]; then if [ "${actual_value}" != "${correct_value}" ]; then inc_secure "${description} for Storage Container \"${container_name}\" on Storage Account \"${storage_account}\" has \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for Storage Container \"${container_name}\" on Storage Account \"${storage_account}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/storage/check_azure_storage_fs_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_storage_fs_value # # Check Azure Storage File System value # # This requires the Azure CLI to be installed and configured #. check_azure_storage_fs_value () { description="${1}" storage_account="${2}" file_system="${3}" query_string="${4}" function="${5}" correct_value="${6}" print_function "check_azure_storage_fs_value" check_message "${description} for File System \"${file_system}\" for Storage Account \"${storage_account}\" has Parameter \"${query_string}\" \"${function}\" to \"${correct_value}\"" command="az storage fs show --account-name \"${storage_account}\" --name \"${file_system}\" --query \"${query_string}\" --auth-mode \"${azure_auth_mode}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "${description} for File System \"${file_system}\" on Storage Account \"${storage_account}\" has \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for File System \"${file_system}\" on Storage Account \"${storage_account}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" fi elif [ "${function}" = "ne" ]; then if [ "${actual_value}" != "${correct_value}" ]; then inc_secure "${description} for File System \"${file_system}\" on Storage Account \"${storage_account}\" has \"${query_string}\" \"${function}\" to \"${correct_value}\"" else inc_insecure "${description} for File System \"${file_system}\" on Storage Account \"${storage_account}\" does not have \"${query_string}\" \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/vaults/check_azure_backup_vault_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_backup_vault_value # # Check Azure Backup value # # This requires the Azure CLI to be installed and configured #. check_azure_backup_vault_value () { description="${1}" vault_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" set_name="${7}" print_function "check_azure_backup_vault_value" check_message "Azure Backup Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az dataprotection backup-vault show --name \"${vault_name}\" --resource-group \"${resource_group}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Backup Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Backup Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "properties.encryption.keyUri" ]; then fix_message "az keyvault set-policy --name --object-id --key-permissions get wrapKey unwrapKey" fix_message "az backup vault encryption enable --resource-group --vault-name --key-uri " else if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az backup vault update --name \"${vault_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az backup vault update --name \"${vault_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${correct_value}\"" ;; esac fi fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure Backup Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "properties.encryption.keyUri" ]; then fix_message "az keyvault set-policy --name --object-id --key-permissions get wrapKey unwrapKey" fix_message "az backup vault encryption enable --resource-group --vault-name --key-uri " else if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az backup vault update --name \"${vault_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az backup vault update --name \"${vault_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${correct_value}\"" ;; esac fi fi else inc_secure "Azure Backup Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/vaults/check_azure_key_vault_key_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_key_vault_key_value # # Check Azure Key Vault key value # # This requires the Azure CLI to be installed and configured # Audit account needs to have the 'Key Vault Reader' role # To do any changes to the key vaults, the 'Key Vault Administrator' role is required #. check_azure_key_vault_key_value () { key_vault="${1}" key_name="${2}" parameter_name="${3}" function="${4}" correct_value="${5}" policy_name="${6}" action_value="${7}" print_function "check_azure_key_vault_key_value" check_message "Key \"${key_name}\" in key vault \"${key_vault}\" with parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" if [ "${policy_name}" = "" ]; then command="az keyvault key show --vault-name \"${key_vault}\" --name \"${key_name}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) else if [ "${parameter_name}" = "" ]; then query_string="lifetimeActions[?contains(action, '${action_value}')]" else query_string="lifetimeActions[?contains(action, '${action_value}')].${parameter_name}" fi command="az keyvault key ${policy_name} show --vault-name \"${key_vault}\" --name \"${key_name}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) fi if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Key \"${key_name}\" in key vault \"${key_vault}\" with parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Key \"${key_name}\" in key vault \"${key_vault}\" with parameter \"${parameter_name}\" is not \"${function}\" to \"${correct_value}\"" fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Key \"${key_name}\" in key vault \"${key_vault}\" with parameter \"${parameter_name}\" is not \"${function}\" to \"${correct_value}\"" else inc_secure "Key \"${key_name}\" in key vault \"${key_vault}\" with parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/vaults/check_azure_key_vault_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_key_vault_value # # Check Azure Key Vault value # # This requires the Azure CLI to be installed and configured # Audit account needs to have the 'Key Vault Reader' role # To do any changes to the key vaults, the 'Key Vault Administrator' role is required #. check_azure_key_vault_value () { resource_name="${1}" resource_group="${2}" parameter_name="${3}" function="${4}" correct_value="${5}" set_name="${6}" print_function "check_azure_key_vault_value" check_message "Key vault with resource name \"${resource_name}\" in resource group \"${resource_group}\" with parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" command="az keyvault show --resource-group \"${resource_group}\" --name \"${resource_name}\" --query \"${parameter_name}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Key vault with resource name \"${resource_name}\" in resource group \"${resource_group}\" with parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Key vault with resource name \"${resource_name}\" in resource group \"${resource_group}\" with parameter \"${parameter_name}\" is not \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then fix_message "az keyvault update --resource-group ${resource_group} --name ${resource_name} ${set_name} ${correct_value}" fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Key vault with resource name \"${resource_name}\" in resource group \"${resource_group}\" with parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" if [ ! "${set_name}" = "" ]; then fix_message "az keyvault update --resource-group ${resource_group} --name ${resource_name} ${set_name} ${correct_value}" else if [ "${parameter_name}" = "properties.privateEndpointConnections" ]; then fix_message "1. To create an endpoint, run the following command:" fix_message "az network private-endpoint create --resource-group --vnet-name --subnet --name \ " fix_message "--private-connection-resource-id \"/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/\" \ " fix_message "--group-ids vault --connection-name --location --manual-request" fix_message "2. To manually approve the endpoint request, run the following command:" fix_message "az keyvault private-endpoint-connection approve --resource-group --vault-name –name " fix_message "3. Determine the Private Endpoint's IP address to connect the Key Vault to the Private DNS you have previously created:" fix_message "4. Look for the property networkInterfaces then id; the value must be placed in the variable within step 7." fix_message "az network private-endpoint show -g -n " fix_message "5. Look for the property networkInterfaces then id; the value must be placed on in step 7." fix_message "az network nic show --ids " fix_message "6. Create a Private DNS record within the DNS Zone you created for the Private Endpoint:" fix_message "az network private-dns record-set a add-record -g -z \"privatelink.vaultcore.azure.net\" -n -a " fix_message "7. nslookup the private endpoint to determine if the DNS record is correct:" fix_message "nslookup .vault.azure.net" fix_message "nslookup .privatelink.vaultcore.azure.net" fi fi else inc_secure "Key vault with resource name \"${resource_name}\" in resource group \"${resource_group}\" with parameter \"${parameter_name}\" is \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/azure/vaults/check_azure_recovery_services_vault_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_azure_recovery_services_vault_value # # Check Azure Recovery Services Vault value # # This requires the Azure CLI to be installed and configured #. check_azure_recovery_services_vault_value () { description="${1}" vault_name="${2}" resource_group="${3}" query_string="${4}" function="${5}" correct_value="${6}" set_name="${7}" print_function "check_azure_recovery_services_vault_value" check_message "Azure Recovery Services Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" command="az dataprotection backup-vault show --name \"${vault_name}\" --resource-group \"${resource_group}\" --query \"${query_string}\" --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${function}" = "eq" ]; then if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure Recovery Services Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" else inc_insecure "Azure Recovery Services Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "properties.encryption.keyUri" ]; then fix_message "az keyvault set-policy --name --object-id --key-permissions get wrapKey unwrapKey" fix_message "az dataprotection backup-vault encryption enable --resource-group --vault-name --key-uri " else if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az dataprotection backup-vault update --name \"${vault_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az dataprotection backup-vault update --name \"${vault_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${correct_value}\"" ;; esac fi fi fi else if [ "${actual_value}" = "${correct_value}" ]; then inc_insecure "Azure Recovery Services Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is not \"${function}\" to \"${correct_value}\"" if [ "${query_string}" = "properties.encryption.keyUri" ]; then fix_message "az keyvault set-policy --name --object-id --key-permissions get wrapKey unwrapKey" fix_message "az dataprotection backup-vault encryption enable --resource-group --vault-name --key-uri " else if [ ! "${set_name}" = "" ]; then case "${set_name}" in "--"*) fix_message "az dataprotection backup-vault update --name \"${vault_name}\" --resource-group \"${resource_group}\" ${set_name} \"${correct_value}\"" ;; *) fix_message "az dataprotection backup-vault update --name \"${vault_name}\" --resource-group \"${resource_group}\" --set \"${set_name}\"=\"${correct_value}\"" ;; esac fi fi else inc_secure "Azure Recovery Services Vault ${description} for vault \"${vault_name}\" with resource group \"${resource_group}\" and parameter \"${query_string}\" is \"${function}\" to \"${correct_value}\"" fi fi } ================================================ FILE: functions/command/check_command_output.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_command_output # # Code to test command output #. check_command_output () { print_function "check_command_output" if [ "${os_name}" = "SunOS" ]; then command_name="${1}" if [ "${command_name}" = "getcond" ]; then get_command="auditconfig -getcond |cut -f2 -d'=' |sed 's/ //g'" fi if [ "${command_name}" = "getpolicy" ]; then get_command="auditconfig -getpolicy |head -1 |cut -f2 -d'=' |sed 's/ //g'" correct_value="argv,cnt,zonename" audit_command="auditconfig -setpolicy" fi if [ "${command_name}" = "getnaflages" ]; then get_command="auditconfig -getpolicy |head -1 |cut -f2 -d'=' |sed 's/ //g' |cut -f1 -d'('" correct_value="lo" audit_command="auditconfig -setnaflags" fi if [ "${command_name}" = "getflages" ]; then get_command="auditconfig -getflags |head -1 |cut -f2 -d'=' |sed 's/ //g' |cut -f1 -d'('" correct_value="lck,ex,aa,ua,as,ss,lo,ft" audit_command="auditconfig -setflags" fi if [ "${command_name}" = "getplugin" ]; then get_command="auditconfig -getplugin audit_binfile |tail-1 |cut -f3 -d';'" correct_value="p_minfree=1" audit_command="auditconfig -setplugin audit_binfile active" fi if [ "${command_name}" = "userattr" ]; then get_command="userattr audit_flags root" correct_value="lo,ad,ft,ex,lck:no" audit_command="auditconfig -setplugin audit_binfile active" fi if [ "${command_name}" = "getcond" ]; then set_command="auditconfig -conf" else if [ "${command_name}" = "getflags" ]; then set_command="${audit_command} lo,ad,ft,ex,lck" else set_command="${audit_command} ${correct_value}" fi fi log_file="${command_name}.log" check_value=$( ${get_command} ) if [ "${audit_mode}" != 2 ]; then string="Command \"${command_name}\" returns \"${correct_value}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_command_output_${command_name}_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command} |grep '${correct_value}'\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${check_value}" != "${correct_value}" ]; then inc_insecure "Command \"${command_name}\" does not return correct value" else inc_secure "Command \"${command_name}\" returns correct value" fi update_log "${log_file}" "${audit_command}" lock_message="Command \"${command_name}\" to correct value" lock_command="${set_command}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then restore_message="Restoring: Previous value for \"${command_name}\"" if [ "${command_name}" = "getcond" ]; then restore_command="${audit_command}" execute_restore "${restore_command}" "${restore_message}" "sudo" else restore_string=$( cat "${restore_file}" ) restore_command="${audit_command} ${restore_string}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi } ================================================ FILE: functions/command/check_command_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_command_value # # Audit command output values # # Depending on the command_name send an appropriate check_command and set_command are set # If the current_value is not the correct_value then it is fixed if run in lockdown mode # A copy of the value is stored in a log file, which can be restored #. check_command_value () { command_name="${1}" parameter_name="${2}" correct_value="${3}" service_name="${4}" print_function "check_command_value" if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${command_name}.log" if [ -f "${restore_file}" ]; then parameter_name=$( grep "${parameter_name}" "${restore_file}" | cut -f1 -d',' ) correct_value=$( grep "${parameter_name}" "${restore_file}" | cut -f2 -d',' ) package_test=$( echo "${parameter_name}" | grep "[A-z]" ) if [ -n "${package_test}" ]; then verbose_message "Returning \"${parameter_name}\" to \"${correct_value}\"" if [ "${command_name}" = "routeadm" ]; then if [ "${correct_value}" = "disabled" ]; then set_command="routeadm -d" else set_command="routeadm -e" fi eval "${set_command} ${parameter_name}" else eval "${set_command} ${parameter_name}=${correct_value}" package_test=$( echo "${parameter_name}" | grep "tcp_trace" ) if [ -n "${package_test}" ]; then svcadm refresh svc:/network/inetd fi fi fi fi else if [ "${parameter_name}" = "tcp_wrappers" ]; then string="Service \"${service_name}\" has \"${parameter_name}\" set to \"${correct_value}\"" else string="Output of command \"${command_name}\" parameter \"${parameter_name}\" is \"${correct_value}\"" fi check_message "${string}" fi if [ "${command_name}" = "inetadm" ]; then check_command="inetadm -l ${service_name}" set_command="inetadm -m ${service_name}" current_value=$( $check_command | grep "${parameter_name}" | awk '{print $2}' | cut -f2 -d'=' ) fi if [ "${command_name}" = "routeadm" ]; then check_command="routeadm -p ${parameter_name}" current_value=$( $check_command | awk '{print $3}' | cut -f2 -d'=' ) if [ "${correct_value}" = "disabled" ]; then set_command="routeadm -d" else set_command="routeadm -e" fi lock_command="${set_command} ${parameter_name}" else lock_command="${set_command} ${parameter_name}=${correct_value}" fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_command_value_${command_name}_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"$check_command\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${lock_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi log_file="${command_name}.log" if [ "${current_value}" != "${correct_value}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Parameter \"${parameter_name}\" not set to \"${correct_value}\"" if [ "${command_name}" = "routeadm" ]; then if [ "${correct_value}" = "disabled" ]; then set_command="routeadm -d" else set_command="routeadm -e" fi lock_command="${set_command} ${parameter_name}" fix_message "${lock_command}" else lock_command="${set_command} ${parameter_name}=${correct_value}" fix_message "${lock_command}" fi else if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${parameter_name},${current_value}" lock_message="Parameter ${parameter_name} to ${correct_value}" if [ "${command_name}" = "routeadm" ]; then if [ "${correct_value}" = "disabled" ]; then set_command="routeadm -d" else set_command="routeadm -e" fi lock_command="${set_command} ${parameter_name}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else lock_command="${set_command} ${parameter_name}=${correct_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi else if [ "${audit_mode}" != 2 ]; then if [ "${audit_mode}" = 1 ]; then if [ "${parameter_name}" = "tcp_wrappers" ]; then inc_secure "Service \"${service_name}\" already has \"${parameter_name}\" set to \"${correct_value}\"" else inc_secure "Output for command \"${command_name}\" parameter \"${parameter_name}\" already set to \"${correct_value}\"" fi fi fi fi } ================================================ FILE: functions/darwin/check_dscl.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_dscl # # Function to check dscl output under OS X #. check_dscl () { if [ "${os_name}" = "Darwin" ]; then file="${1}" param="${2}" value="${3}" print_function "check_dscl" dir="/var/db/dslocal/nodes/Default" if [ "${audit_mode}" != 2 ]; then string="Parameter \"${param}\" is set to \"${value}\" in \"${file}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_dscl_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"sudo dscl . -read ${file} ${param} 2> /dev/null\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"sudo dscl . -create ${file} ${param} '${value}'\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi command="sudo dscl . -read \"${file}\" \"${param}\" 2> /dev/null | wc -l | sed \"s/ //g\"" command_message "${command}" d_check=$( eval "${command}" ) if [ "${d_check}" = "0" ]; then check="not-found" else command="sudo dscl . -read \"${file}\" \"${param}\" 2> /dev/null" command_message "${command}" check=$( eval "${command}" ) fi if [ "${check}" != "${value}" ]; then inc_insecure "Parameter \"${param}\" not set to \"${value}\" in \"${file}\"" fix_message "sudo dscl . -create ${file} ${param} \"${value}\"" if [ "${audit_mode}" = 0 ]; then backup_file "${dir}/${file}" lock_message="Parameter \"${param}\" to \"${value}\" in ${file}" lock_command="dscl . -create ${file} ${param} ${value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Parameter \"${param}\" is set to \"${value}\" in \"${file}\"" fi fi else restore_file "${dir}/${file}" "${restore_dir}" fi fi } ================================================ FILE: functions/darwin/check_launchctl_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_launchctl_service # # Function to check launchctl output under OS X #. check_launchctl_service () { if [ "${os_name}" = "Darwin" ]; then launchctl_service="${1}" required_status="${2}" print_function "check_launchctl_service" log_file="${launchctl_service}.log" if [ "${required_status}" = "on" ] || [ "${required_status}" = "enable" ]; then required_status="enabled" change_status="load" else required_status="disabled" change_status="unload" fi get_command="launchctl list |grep ${launchctl_service} |awk '{print \$3}'" set_command="sudo launchctl ${change_status} -w ${launchctl_service}.plist" check_value=$( eval "${get_command}" ) if [ "${check_value}" = "${launchctl_service}" ]; then actual_status="enabled" else actual_status="disabled" fi if [ "${audit_mode}" != 2 ]; then string="Service \"${launchctl_service}\" is \"${required_status}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_launchctl_service_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${actual_status}" != "${required_status}" ]; then inc_insecure "Service \"${launchctl_service}\" is \"${actual_status}\"" lock_command="sudo launchctl ${change_status} -w ${launchctl_service}.plist" lock_message="Service ${launchctl_service} to ${required_status}" update_log "${log_file}" "${actual_status}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "Service \"${launchctl_service}\" is \"${required_status}\"" fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then restore_status=$( cat "${log_file}" ) if [ "${restore_status}" = "enabled" ]; then change_status="load" else change_status="unload" fi if [ "${restore_status}" != "${actual_status}" ]; then restore_message="Restoring ${launchctl_service} to ${change_status}" restore_command="launchctl ${change_status} -w ${launchctl_service}.plist" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi } ================================================ FILE: functions/darwin/check_osx_defaults.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_osx_defaults # # Function to check defaults under OS X #. check_osx_defaults () { if [ "${os_name}" = "Darwin" ]; then defaults_file="${1}" defaults_parameter="${2}" defaults_value="${3}" defaults_type="${4}" if [ "${defaults_type}" = "dict" ]; then defaults_second_value="${5}" defaults_second_type="${6}" defaults_user="${7}" else defaults_host="${5}" defaults_user="${6}" fi print_function "check_osx_defaults" defaults_read="read" defaults_write="write" backup_file=${defaults_file} if [ ! "${defaults_host}" = "currentHost" ]; then defaults_user="${defaults_host}" defaults_host="" fi if [ "${defaults_user}" = "" ]; then defaults_command="sudo defaults" else defaults_command="sudo -u ${defaults_user} defaults" fi if [ "${audit_mode}" != 2 ]; then if [ "${defaults_user}" = "" ]; then string="Parameter \"${defaults_parameter}\" is set to \"${defaults_value}\" in \"${defaults_file}\"" else string="Parameter \"${defaults_parameter}\" is set to \"${defaults_value}\" in \"${defaults_file}\" for user \"${defaults_user}\"" fi check_message "${string}" if [ "${defaults_host}" = "currentHost" ]; then defaults_read="-currentHost ${defaults_read}" defaults_write="-currentHost ${defaults_write}" backup_file="$HOME/Library/Preferences/ByHost/${defaults_file}*" defaults_command="defaults" fi command="${defaults_command} ${defaults_read} ${defaults_file} ${defaults_parameter} 2> /dev/null | wc -l |sed 's/ //g'" command_message "${command}" null_check=$( eval "${command}" ) if [ "$null_check" = "0" ]; then check_value="not-found" else command="${defaults_command} ${defaults_read} ${defaults_file} ${defaults_parameter} 2> /dev/null | sed 's/^ //g' |grep '0' |wc -l |sed 's/ //g'" command_message "${command}" zero_check=$( eval "${command}" ) if [ "${zero_check}" = "1" ]; then check_value="0" else command="${defaults_command} ${defaults_read} ${defaults_file} ${defaults_parameter} 2> /dev/null | sed 's/^ //g'" command_message "${command}" check_value=$( eval "${command}" ) fi fi temp_value="${defaults_value}" if [ "${defaults_type}" = "bool" ]; then if [ "${defaults_value}" = "no" ]; then temp_value=0 fi if [ "${defaults_value}" = "yes" ]; then temp_value=1 fi fi if [ "${check_value}" != "${temp_value}" ]; then if [ "${defaults_user}" = "" ]; then inc_insecure "Parameter \"${defaults_parameter}\" not set to \"${defaults_value}\" in \"${defaults_file}\"" else inc_insecure "Parameter \"${defaults_parameter}\" not set to \"${defaults_value}\" in \"${defaults_file}\" for user \"${defaults_user}\"" fi if [ "${defaults_value}" = "" ]; then fix_message "${defaults_command} delete ${defaults_file} ${defaults_parameter}" set_command="${defaults_command} delete ${defaults_file} ${defaults_parameter}" else if [ "${defaults_type}" = "bool" ]; then fix_message "${defaults_command} write ${defaults_file} ${defaults_parameter} -bool \"${defaults_value}\"" set_command="${defaults_command} write ${defaults_file} ${defaults_parameter} -bool \"${defaults_value}\"" else if [ "${defaults_type}" = "int" ]; then fix_message "${defaults_command} write ${defaults_file} ${defaults_parameter} -int ${defaults_value}" set_command="${defaults_command} write ${defaults_file} ${defaults_parameter} -int ${defaults_value}" else if [ "${defaults_type}" = "dict" ]; then if [ "${defaults_second_type}" = "bool" ]; then fix_message "${defaults_command} write ${defaults_file} ${defaults_parameter} -dict ${defaults_value} -bool ${defaults_second_value}" set_command="${defaults_command} write ${defaults_file} ${defaults_parameter} -dict ${defaults_value} -bool ${defaults_second_value}" else if [ "${defaults_second_type}" = "int" ]; then fix_message "${defaults_command} write ${defaults_file} ${defaults_parameter} -dict ${defaults_value} -int ${defaults_second_value}" set_command="${defaults_command} write ${defaults_file} ${defaults_parameter} -dict ${defaults_value} -int ${defaults_second_value}" fi fi else fix_message "${defaults_command} write ${defaults_file} ${defaults_parameter} \"${defaults_value}\"" set_command="${defaults_command} write ${defaults_file} ${defaults_parameter} \"${defaults_value}\"" fi fi fi fi if [ "${audit_mode}" = 0 ]; then backup_file "${backup_file}" string="Parameter ${defaults_parameter} to ${defaults_value} in ${defaults_file}" lock_message="${string}" if [ "${defaults_value}" = "" ]; then lock_command="${defaults_command} delete ${defaults_file} ${defaults_parameter}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else if [ "${defaults_type}" = "bool" ]; then lock_command="${defaults_command} write ${defaults_file} ${defaults_parameter} -bool ${defaults_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else if [ "${defaults_type}" = "int" ]; then lock_command="${defaults_command} write ${defaults_file} ${defaults_parameter} -int ${defaults_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" if [ "${defaults_file}" = "/Library/Preferences/com.apple.Bluetooth" ]; then killall -HUP blued fi else if [ "${defaults_type}" = "dict" ]; then if [ "${defaults_second_type}" = "bool" ]; then lock_command="${defaults_command} write ${defaults_file} ${defaults_parameter} -dict ${defaults_value} -bool ${defaults_second_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else if [ "${defaults_second_type}" = "int" ]; then lock_command="${defaults_command} write ${defaults_file} ${defaults_parameter} -dict ${defaults_value} -int ${defaults_second_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi else lock_command="${defaults_command} write ${defaults_file} ${defaults_parameter} \"${defaults_value}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi fi fi get_command="${defaults_command} ${defaults_read} ${defaults_file} ${defaults_parameter} 2>&1 |grep ${defaults_value}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_osx_defaults_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi else if [ "${defaults_user}" = "" ]; then inc_secure "Parameter \"${defaults_parameter}\" is set to \"${defaults_value}\" in \"${defaults_file}\"" else inc_secure "Parameter \"${defaults_parameter}\" is set to \"${defaults_value}\" in \"${defaults_file}\" for user \"${defaults_user}\"" fi fi else restore_file "${backup_file}" "${restore_dir}" fi fi } check_osx_defaults_dict () { check_osx_defaults "${1}" "${2}" "${3}" "${4}" "${5}" "${6}" "" "" } check_osx_defaults_int () { check_osx_defaults "${1}" "${2}" "${3}" "int" "" "" "" "" } check_osx_defaults_bool () { check_osx_defaults "${1}" "${2}" "${3}" "bool" "" "" "" "" } check_osx_defaults_string () { check_osx_defaults "${1}" "${2}" "${3}" "string" "" "" "" "" } check_osx_defaults_user () { check_osx_defaults "${1}" "${2}" "${3}" "${4}" "${5}" "" "" "" } check_osx_defaults_host () { check_osx_defaults "${1}" "${2}" "${3}" "${4}" "currentHost" "" "" "" } check_osx_defaults_value () { check_osx_defaults "${1}" "${2}" "${3}" "" "" "" "" "" } ================================================ FILE: functions/darwin/check_osx_systemsetup.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_osx_systemsetup # # Function to systemsetup output under OS X #. check_osx_systemsetup () { if [ "${os_name}" = "Darwin" ]; then if [ "${os_version}" -ge 12 ]; then param="${1}" value="${2}" print_function "check_osx_systemsetup" log_file="systemsetup_${param}.log" if [ "${audit_mode}" != 2 ]; then string="Parameter \"${param}\" is set to \"${value}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_osx_systemsetup_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"sudo systemsetup -${param} |cut -f2 -d: |sed 's/ //g' |tr '[:upper:]' '[:lower:]'\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sudo systemsetup -${param} ${value}" echo " when: ${ansible_value}.rc == 0 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi command="sudo systemsetup -${param} | cut -f2 -d: | sed 's/ //g' | tr '[:upper:]' '[:lower:]'" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" != "${value}" ]; then inc_insecure "Parameter \"${param}\" not set to \"${value}\"" update_log "${log_file}" "${check_file}" lock_command="systemsetup -${param} ${value}" lock_message="Parameter \"${param}\" to \"${value}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "Parameter \"${param}\" is set to \"${value}\"" fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then command="sudo systemsetup -${param} | cut -f2 -d: | sed 's/ //g' | tr '[:upper:]' '[:lower:]'" command_message "${command}" now=$( eval "${command}" ) old=$( cat "${restore_file}" ) if [ "${now}" != "${old}" ]; then restore_command="systemsetup -${param} ${old}" restore_message="Parameter \"${param}\" back to \"${old}\"" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi fi } ================================================ FILE: functions/darwin/check_pmset.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_pmset # # Check Apple Power Management settings #. check_pmset() { if [ "${os_name}" = "Darwin" ]; then service="${1}" value="${2}" print_function "check_pmset" state="${value}" if [ "${value}" = "off" ]; then value="0" fi if [ "${value}" = "on" ]; then value="1" fi if [ "${value}" = "0" ]; then state="off" fi if [ "${value}" = "1" ]; then state="on" fi log_file="pmset_${service}.log" command="pmset -g | grep \"${service}\" | awk '{print \$2}' | grep -c \"${value}\" | sed \"s/ //g\"" command_message "${command}" actual_test=$( eval "${command}" ) if [ "$actual_test" = "0" ]; then actual_value="not-found" else command="pmset -g | grep \"${service}\" | awk '{print \$2}' | grep \"${value}\"" command_message "${command}" actual_value=$( eval "${command}" ) fi if [ "${audit_mode}" != 2 ]; then string="Sleep is disabled when powered" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_pmset_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"pmset -g | grep ${service} |awk '{print \$2}' |grep ${value}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"pmset -c ${service} ${value}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ ! "${actual_value}" = "${value}" ]; then inc_insecure "Service \"${service}\" is not \"${state}\"" lock_command="echo \"${state}\" > ${work_dir}/${log_file} ; pmset -c ${service} ${value}" lock_message="Service \"${service}\" to \"${state}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "Service \"${service}\" is \"${state}\"" fi else restore_file=$retore_dir/${log_file} if [ -f "${restore_file}" ]; then restore_value=$( cat "${restore_file}" ) if [ "${restore_value}" != "${actual_value}" ]; then restore_message="Wake on lan to enabled" restore_command="pmset -c ${service} ${restore_value}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi } ================================================ FILE: functions/darwin/check_sysadminctl.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_sysadminctl # # Function to check sysadminctl output under OS X #. check_sysadminctl () { if [ "${os_name}" = "Darwin" ]; then param="${1}" value="${2}" print_function "check_sysadminctl" log_file="sysadminctl.log" if [ "${value}" = "off" ]; then search_value="disabled" other_value="on" fi if [ "${value}" = "on" ]; then search_value="enabled" other_value="off" fi if [ "${audit_mode}" != 2 ]; then string="Parameter \"${param}\" is set to \"${value}\"" check_message "${string}" get_command="sudo sysadminctl -${param} status > /dev/null 2>&1 |grep ${search_value}" set_command="sudo sysadminctl -${param} ${value}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_sysadminctl_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: \"${search_value}\" not in ${ansible_value}" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi command="sudo sysadminctl -${param} status > /dev/null 2>&1 | grep ${search_value} | wc -l | sed 's/ //g'" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" != "1" ]; then inc_insecure "Parameter \"${param}\" not set to \"${value}\"" fix_message "sudo sysadminctl -${param} ${value}" if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${param},${other_value}" lock_message="Parameter \"${param}\" to \"${value}\"" lock_command="${set_command}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Parameter \"${param}\" is set to \"${value}\"" fi fi else restore_file="${restore_dir}/${log_file}" restore_value=$( grep "^${param}" "${restore_file}" |cut -f2 -d, ) restore_message="Parameter \"${param}\" to \"${restore_value}\"" restore_command="sudo sysadminctl -${param} ${restore_value}" execute_restore "${restore_command}" "${restore_message}\"" "sudo" fi fi } ================================================ FILE: functions/docker/audit_docker.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_docker_all # # Audit Docker # # All the Docker specific tests #. audit_docker_all () { print_function "audit_docker_all" audit_auditd audit_docker_users audit_docker_daemon audit_docker_network audit_docker_logging audit_docker_monitoring audit_docker_security } # funct_audit_docker # # Audit Docker #. funct_audit_docker () { audit_mode="${1}" print_function "funct_audit_docker" audit_docker_all print_results } ================================================ FILE: functions/docker/check_dockerd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2009 # shellcheck disable=SC2016 # check_dockerd # # Check dockerd parameter value #. check_dockerd () { used="${1}" type="${2}" param="${3}" value="${4}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then print_function "check_dockerd" if [ "${type}" = "config" ]; then if [ "${value}" ]; then check_message "Docker \"${type}\" parameter \"${param}\" has value \"${value}\"" else check_message "Docker \"${type}\" parameter \"${param}\" has no value" fi else if [ "${value}" ]; then check_message "Docker \"${type}\" parameter \"${param}\" is \"${used}\" and has value \"${value}\"" else check_message "Docker \"${type}\" parameter \"${param}\" is \"${used}\"" fi fi case "${type}" in "daemon") command="ps -ef | grep dockerd | grep \"${param}\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ] && [ "${value}" ] && [ "${used}" = "unused" ]; then command="ps -ef | grep dockerd | grep \"${param}\" | grep \"${value}\"" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_insecure "Docker parameter \"${param}\" is not set to \"${value}\"" else inc_secure "Docker parameter \"${param}\" is set to \"${value}\"" fi else if [ "${used}" = "used" ] && [ ! "${check}" ]; then inc_insecure "Docker parameter \"${param}\" is not used" else inc_secure "Docker parameter \"${param}\" is \"${used}\"" fi fi ;; "info") command="docker info 2> /dev/null |grep \"${param}\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ] && [ "${value}" ] && [ "${used}" = "unused" ]; then command="docker info 2> /dev/null | grep \"${param}\" | grep \"${value}\"" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_insecure "Docker parameter \"${param}\" is not set to \"${value}\"" else inc_secure "Docker parameter \"${param}\" is set to \"${value}\"" fi else inc_secure "Docker parameter \"${param}\" is \"${used}\"" fi ;; "kernel") OFS=$IFS IFS=$(printf '\n+'); IFS=${IFS%?} command="docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: CapAdd={{ .HostConfig.CapAdd }}' 2> /dev/null" command_message "${command}" docker_info=$( eval "${command}" ) if [ ! "${docker_info}" ]; then verbose_message "No Docker instances" notice fi for info in ${docker_info}; do command="echo \"${info}\" | cut -f1 -d:" command_message "${command}" docker_id=$( eval "${command}" ) command="echo \"${info}\" | cut -f2 -d: | cut -f2 -d= | grep \"${param}\"" command_message "${command}" check=$( eval "${command}" ) if [ "${used}" = "used" ]; then if [ "${profile}" ]; then inc_secure "Docker instance \"${docker_id}\" has capability \"${param}\"" else inc_insecure "Docker instance \"${docker_id}\" does not have capability \"${param}\"" fi else if [ "${profile}" ]; then inc_secure "Docker instance \"${docker_id}\" does not have capability \"${param}\"" else inc_insecure "Docker instance \"${docker_id}\" has capability \"${param}\"" fi command="docker inspect --format '{{ .Id }}: CapAdd={{ .HostConfig.CapDrop }}' \"${docker_id}\" | cut -f2 -d= | grep \"${param}\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ]; then inc_secure "Docker instance \"${docker_id}\" forcibly drops capability \"${param}\"" else inc_insecure "Docker instance \"${docker_id}\" does not forcibly capability \"${param}\"" fi fi done IFS=$OFS ;; "config") OFS=$IFS IFS=$(printf '\n+'); IFS=${IFS%?} case ${param} in "AppArmorProfile") command="docker ps --quiet --all | xargs docker inspect --format \"{{ .Id }}: ${param}={{ .${param} }}\" 2> /dev/null" command_message "${command}" docker_info=$( eval "${command}" ) ;; "User") command="docker ps --quiet --all | xargs docker inspect --format \"{{ .Id }}: ${param}={{ .Config.${param} }}\" 2> /dev/null" command_message "${command}" docker_info=$( eval "${command}" ) ;; "Ports") command="docker ps --quiet --all | xargs docker inspect --format \"{{ .Id }}: ${param}={{ .NetworkSettings.${param} }}\" 2> /dev/null" command_message "${command}" docker_info=$( eval "${command}" ) ;; "Propagation") command="docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: Propagation={{range $mnt := .Mounts}} {{json $mnt.Propagation}} {{end}}' 2> /dev/null" command_message "${command}" docker_info=$( eval "${command}" ) ;; "Health") command="docker ps --quiet | xargs docker inspect --format '{{ .Id }}: Health={{ .State.Health.Status }}' 2> /dev/null" command_message "${command}" docker_info=$( eval "${command}" ) ;; *) command="docker ps --quiet --all | xargs docker inspect --format \"{{ .Id }}: ${param}={{ .HostConfig.${param} }}\" 2> /dev/null" command_message "${command}" docker_info=$( eval "${command}" ) ;; esac if [ ! "${docker_info}" ]; then verbose_message "No Docker instances with \"${param}\" set" notice fi for info in ${docker_info}; do command="echo \"${info}\" | cut -f1 -d:" command_message "${command}" docker_id=$( eval "${command}" ) case ${used} in "notequal") command="echo \"${info}\" | cut -f2 -d: | cut -f2 -d= | grep -v \"\\[\\]\"" command_message "${command}" profile=$( eval "${command}" ) if [ ! "${value}" ]; then if [ "${profile}" ]; then inc_secure "Docker instance \"${docker_id}\" does not have parameter \"${param}\"" else inc_insecure "Docker instance \"${docker_id}\" has parameter \"${param}\"" fi else if [ ! "${profile}" = "${value}" ]; then inc_secure "Docker instance \"${docker_id}\" does not have parameter \"${param}\" set to \"${value}\"" else inc_insecure "Docker instance \"${docker_id}\" has parameter \"${param}\" set to \"${value}\"" fi fi ;; "equal") command="echo \"${info}\" | cut -f2 -d: | cut -f2 -d= | grep -v \"\[\]\"" command_message "${command}" profile=$( eval "${command}" ) if [ ! "${value}" ]; then if [ ! "${profile}" ]; then inc_secure "Docker instance \"${docker_id}\" does not have parameter \"${param}\"" else inc_insecure "Docker instance \"${docker_id}\" has parameter \"${param}\"" fi else if [ "${profile}" = "${value}" ]; then inc_secure "Docker instance \"${docker_id}\" does not have parameter \"${param}\" set to \"${value}\"" else inc_insecure "Docker instance \"${docker_id}\" does not have parameter \"${param}\" set to \"${value}\"" fi fi ;; "notinclude") command="echo \"${info}\" | cut -f2 -d: | cut -f2 -d= | grep \"${param}\"" command_message "${command}" profile=$( eval "${command}" ) if [ ! "${profile}" ]; then inc_secure "Docker instance \"${docker_id}\" parameter \"${param}\" does not include \"${value}\"" else inc_insecure "Docker instance \"${docker_id}\" parameter \"${param}\" includes \"${value}\"" fi ;; "include") command="echo \"${info}\" | cut -f2 -d: | cut -f2 -d= | grep \"${param}\"" command_message "${command}" profile=$( eval "${command}" ) if [ "${profile}" ]; then inc_secure "Docker instance \"${docker_id}\" parameter \"${param}\" includes \"${value}\"" else inc_insecure "Docker instance \"${docker_id}\" parameter \"${param}\" does not include \"${value}\"" fi ;; esac done IFS=$OFS ;; esac fi fi } ================================================ FILE: functions/file/audit_search_fs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_search_fs # # Audit Filesystem # # Run various filesystem audits, add support for NetBackup #. audit_search_fs () { if [ "${os_name}" = "SunOS" ]; then print_function "audit_search_fs" verbose_message "Filesystem Search" command="pkginfo -l | grep SYMCnbclt | grep PKG | awk '{print \$2}'" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" != "SYMCnbclt" ]; then audit_bpcd audit_vnetd audit_vopied audit_bpjava_msvc else funct_file_value "/etc/hosts.allow" "bpcd" "colon" " ALL" "hash" funct_file_value "/etc/hosts.allow" "vnetd" "colon" " ALL" "hash" funct_file_value "/etc/hosts.allow" "bpcd" "vopied" " ALL" "hash" funct_file_value "/etc/hosts.allow" "bpcd" "bpjava-msvc" " ALL" "hash" fi audit_extended_attributes fi audit_writable_files audit_suid_files audit_file_perms audit_sticky_bit } ================================================ FILE: functions/file/audit_select.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # funct_audit_select # # Selective Audit #. funct_audit_select () { audit_mode="${1}" module_name="${2}" print_function "funct_audit_select" module_test=$( echo "${module_name}" | grep -c aws ) if [ "$module_test" = "1" ]; then check_aws fi suffix_test=$( echo "${module_name}" | grep -c "\\.sh" ) if [ "${suffix_test}" = "1" ]; then module_name=$( echo "${module_name}" | cut -f1 -d. ) fi module_test=$( echo "${module_name}" | grep -c "full" ) if [ "$module_test" = "0" ]; then function_test=$( echo "${module_name}" | grep -c "audit_" ) if [ "${function_test}" = "0" ]; then module_name="audit_${module_name}" fi fi module_test=$( echo "${module_name}" | grep "audit" ) if [ -n "$module_test" ]; then command="find \"${modules_dir}\" -name \"${module_name}.sh\"" command_message "${command}" file_name=$( eval "${command}" ) if [ -f "${file_name}" ]; then print_audit_info "${module_name}" eval "${module_name}" else warn_message "Audit function \"${module_name}\" does not exist" verbose_message "" "" exit fi print_results else warn_message "Audit function \"${module_name}\" does not exist" verbose_message "" "" fi } ================================================ FILE: functions/file/audit_test_subset.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_test_subset # # Audit Subset for testing #. audit_test_subset () { print_function "audit_test_subset" audit_legacy } ================================================ FILE: functions/file/backup_file.sh ================================================ #!/bin/sh # shellcheck disable=SC2034 # shellcheck disable=SC1090 # shellcheck disable=SC2154 # backup_file # # Backup file #. backup_file () { check_file="${1}" print_function "backup_file" if [ -f "${check_file}" ]; then if [ "${audit_mode}" = 0 ]; then backup_file="${work_dir}${check_file}" if [ ! -f "${backup_file}" ]; then verbose_message "File \"${check_file}\" to \"${backup_file}\"" "backup" command="find \"${check_file}\" | cpio -pdm \"${work_dir}\" 2> /dev/null" command_message "${command}" eval "${command}" if [ "${check_file}" = "/etc/system" ]; then reboot_required=1 verbose_message "Notice: Reboot required" fi check_base=$( basename "${check_file}" ) if [ "${check_base}" = "sshd_config" ]; then verbose_message "Notice: Service restart required for SSH" fi if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Restart ssh service" echo " service:" echo " name: ssh" echo " state: restarted" echo "" fi fi fi else warn_message "File \"${check_file}\" does not exist" fi } ================================================ FILE: functions/file/check_append_file.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_append_file # # Code to append a file with a line # # check_file = The name of the original file # parameter = The parameter/line to add to a file # comment_value = The character used in the file to distinguish a line as a comment #. check_append_file () { check_file="${1}" parameter="${2}" comment_value="${3}" print_function "check_append_file" dir_name=$( dirname "${check_file}" ) if [ ! -f "${check_file}" ]; then warn_message "File \"${check_file}\" does not exist" fi if [ ! -d "${dir_name}" ]; then warn_message "Directory \"${dir_name}\" does not exist" else if [ "${comment_value}" = "star" ]; then comment_value="*" else comment_value="#" fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}${check_file}" restore_file "${check_file}" "${restore_dir}" else secure_string="Parameter \"${parameter}\" is set in \"${check_file}\"" insecure_string="Parameter \"${parameter}\" is not set in \"${check_file}\"" check_message "${secure_string}" if [ ! -f "${check_file}" ]; then inc_insecure "Parameter \"${parameter}\" does not exist in \"${check_file}\"" lock_command="echo \"${parameter}\" >> ${check_file}" lock_message="Parameter \"${parameter}\" in \"${check_file}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" if [ "${parameter}" ]; then if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${secure_string}" echo " lineinfile:" echo " path: ${check_file}" echo " line: '${parameter}'" echo " create: yes" echo "" fi fi else if [ "${parameter}" ]; then if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${secure_string}" echo " lineinfile:" echo " path: ${check_file}" echo " line: '${parameter}'" echo "" fi command="grep -v \"^${comment_value}\" \"${check_file}\" | grep -- \"${parameter}\" | uniq | wc -l | sed \"s/ //g\"" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" != "1" ]; then inc_insecure "${insecure_string}" backup_file "${check_file}" lock_command="echo \"${parameter}\" >> ${check_file}" lock_message="Parameter \"${parameter}\" in \"${check_file}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "${secure_string}" fi fi fi fi fi } ================================================ FILE: functions/file/check_file_comment.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2012 # shellcheck disable=SC2028 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_file_comment # # Check if a file contains a value and comment it out # #. check_file_comment () { file="${1}" search="${2}" comment="${3}" print_function "check_file_comment" line="^(\s*${search}.*)" if [ "${comment}" = "hash" ]; then comment="#" fi string="File ${file} with line containing ${search} is commented out" check_message "${string}" if [ "${audit_mode}" != 2 ]; then if [ -f "${file}" ]; then check=$( grep "${search}" < "${file}" | grep -cv "^${comment}" ) if [ ! "${check}" = "0" ]; then if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " lineinfile:" echo " path: ${check_file}" echo " line: '${line}'" echo " replace: '#\1'" echo " create: yes" echo "" else command="sed 's/${line}/${comment}\1/g' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file}" run_lockdown "${command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" update_log "${log_file}" "${check_file},sed" lock_message="File \"${check_file}\"" lock_command="sed \"s/${line}/${comment}\1/g\" < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi } ================================================ FILE: functions/file/check_file_exists.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_file_exists # # Check to see a file ${exists} and create it or delete it # # check_file = File to check fo # check_${exists} = If equal to no and file ${exists}, delete it # If equal to yes and file doesn't exist, create it #. check_file_exists () { check_file="${1}" check_exists="${2}" print_function "check_file_exists" log_file="file.log" if [ "${check_exists}" = "no" ]; then if [ "${audit_mode}" != 2 ]; then string="File \"${check_file}\" does not exist" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_file_exists_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " stat:" echo " path ${check_file}" echo " register: ${ansible_value}" echo "" echo "- name: Fixing ${string}" echo " file:" echo " path: ${check_file}" echo " state: absent" echo " when: ${ansible_value}.${exists} == True" echo "" fi fi if [ -f "${check_file}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "File \"${check_file}\" ${exists}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" update_log "${log_file}" "${check_file},rm" lock_message="File \"${check_file}\"" lock_command="rm ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "File \"${check_file}\" does not exist" fi fi else if [ "${audit_mode}" != 2 ]; then string="File \"${check_file}\" ${exists}" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="check_file_exists_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " stat:" echo " path ${check_file}" echo " register: stat_result" echo "" echo "- name: Fixing ${string}" echo " file:" echo " path: ${check_file}" echo " state: touch" echo " when: stat_result.${exists} == False" echo "" fi fi if [ ! -f "${check_file}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "File \"${check_file}\" does not exist" fi if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${check_file},touch" lock_message="File \"${check_file}\"" lock_command="touch ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "File \"${check_file}\" ${exists}" fi fi fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi } ================================================ FILE: functions/file/check_file_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2012 # check_file_perms # # Code to check permissions on a file # If running in audit mode it will check permissions and report # If running in lockdown mode it will fix permissions if they # don't match those passed to routine # Takes: # check_file: Name of file # check_perms: Octal of file permissions, eg 755 # check_owner: Owner of file # check_group: Group ownership of file #. check_file_perms () { check_file="${1}" check_perms="${2}" check_owner="${3}" check_group="${4}" print_function "check_file_perms" if [ "${id_check}" = "0" ]; then find_command="find" else find_command="sudo find" fi if [ "${audit_mode}" != 2 ]; then string="File permissions on \"${check_file}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " file:" echo " path: ${check_file}" if [ ! "${check_owner}" = "" ]; then echo " owner: ${check_owner}" fi if [ ! "${check_group}" = "" ]; then echo " group: ${check_group}" fi echo " mode: ${check_perms}" echo "" fi fi if [ ! -e "${check_file}" ]; then if [ "${audit_mode}" != 2 ]; then warn_message "File \"${check_file}\" does not exist" fi return fi if [ "${check_owner}" != "" ]; then command="find \"${check_file}\" -maxdepth 0 -perm \"${check_perms}\" -user \"${check_owner}\" -group \"${check_group}\" 2> /dev/null | wc -l | sed \"s/ //g\"" command_message "${command}" check_result=$( eval "${command}" ) else command="find \"${check_file}\" -maxdepth 0 -perm \"${check_perms}\" 2> /dev/null | wc -l | sed \"s/ //g\"" command_message "${command}" check_result=$( eval "${command}" ) fi log_file="fileperms.log" if [ "${check_result}" != "1" ]; then if [ "${audit_mode}" = 1 ] && [ -n "${check_result}" ]; then inc_insecure "File \"${check_file}\" has incorrect permissions" fix_message "chmod ${check_perms} ${check_file}" if [ "${check_owner}" != "" ]; then if [ "${check_result}" != "1" ]; then fix_message "chown ${check_owner}:${check_group} ${check_file}" fi fi fi if [ "${audit_mode}" = 0 ]; then log_file="${work_dir}/${log_file}" if [ "${os_name}" = "SunOS" ]; then command="truss -vstat -tstat ls -ld \"${check_file}\" 2>&1 | grep 'm=' | tail -1 | awk '{print $3}' | cut -f2 -d'=' | cut -c4-7" command_message "${command}" file_perms=$( eval "${command}" ) else if [ "${os_name}" = "Darwin" ]; then command="stat -f %p \"${check_file}\" | tail -c 4" command_message "${command}" file_perms=$( eval "${command}" ) else command="stat -c %a \"${check_file}\"" command_message "${command}" file_perms=$( eval "${command}" ) fi fi if [ "${os_name}" = "Linux" ]; then command="stat -c \"%U,%G\" \"${check_file}\"" command_message "${command}" file_owner=$( eval "${command}" ) else command="ls -ld \"${check_file}\" | awk '{print \"\$3\",\"\$4\"}'" command_message "${command}" file_owner=$( eval "${command}" ) fi update_log "${log_file}" "${check_file},${file_perms},${file_owner}" lock_message="File \"${check_file}\" to have correct permissions" lock_command="chmod ${check_perms} ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" if [ "${check_owner}" != "" ]; then if [ "${check_result}" != "${check_file}" ]; then lock_message="File \"${check_file}\" to have correct owner" lock_command="chown ${check_owner}:${check_group} ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "File \"${check_file}\" has correct permissions" fi fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then command="grep \"${check_file}\" \"${restore_file}\" | cut -f1 -d," command_message "${command}" restore_check=$( eval "${command}" ) if [ "${restore_check}" = "${check_file}" ]; then restore_info=$( grep "${check_file}" "${restore_file}" ) restore_perms=$( echo "${restore_info}" | cut -f2 -d, ) restore_owner=$( echo "${restore_info}" | cut -f3 -d, ) restore_group=$( echo "${restore_info}" | cut -f4 -d, ) restore_message="File \"${check_file}\" to previous permissions" restore_command="chmod ${restore_perms} ${check_file}" execute_restore "${restore_command}" "${restore_message}" "sudo" if [ "${check_owner}" != "" ]; then if [ "${check_result}" != "${check_file}" ]; then restore_message="File \"${check_file}\" to previous owner" restore_command="chown ${restore_owner}:${restore_group} ${check_file}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi fi } ================================================ FILE: functions/file/check_file_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2086 # shellcheck disable=SC2154 # check_file_value # # Audit file values # # This routine takes the following values # # check_file = The name of the file to check # parameter_name = The parameter to be checked # seperator = Character used to seperate parameter name from it's value (eg =) # correct_value = The value we expect to be returned # comment_value = Character used as a comment (can be #, *, etc) # Needs to be passed as word, e.g. hash, star, bang, semicolon, eq, space, colon # position = E.g. after # search_value = Additional search term to help locate parameter / value # # If the current_value is not the correct_value then it is fixed if run in lockdown mode # A copy of the value is stored in a log file, which can be restored #. check_file_value_with_position () { operator="${1}" check_file="${2}" parameter_name="${3}" separator="${4}" correct_value="${5}" comment_value="${6}" position="${7}" search_value="${8}" print_function "check_file_value_with_position" temp_file=$( basename ${check_file} ) temp_file="${temp_dir}/${temp_file}" dir_name=$( dirname "${check_file}" ) sshd_test=$( echo "${check_file}" | grep -c "sshd_config" | sed "s/ //g" ) if [ ! -f "${check_file}" ]; then warn_message "File \"${check_file}\" does not exist" fi if [ ! -d "${dir_name}" ]; then warn_message "Directory \"${dir_name}\" does not exist" else if [ "${operator}" = "set" ]; then correct_value="[A-Z,a-z,0-9]" operator="is" fi if [ "${comment_value}" = "star" ]; then comment_value="*" else if [ "${comment_value}" = "bang" ]; then comment_value="!" else if [ "${comment_value}" = "semicolon" ]; then comment_value=";" else comment_value="#" fi fi fi sep_test=$( expr "${separator}" : "eq" ) if [ "${sep_test}" = 2 ]; then separator="=" spacer="\=" else sep_test=$( expr "${separator}" : "space" ) if [ "${sep_test}" = 5 ]; then separator=" " spacer=" " else sep_test=$( expr "${separator}" : "colon" ) if [ "${sep_test}" = 5 ]; then separator=":" space=":" fi fi fi if [ "${operator}" = "is" ] || [ "${operator}" = "in" ]; then negative="not" else negative="is" fi if [ "${id_check}" = "0" ] || [ "${os_name}" = "VMkernel" ]; then cat_command="cat" sed_command="sed" echo_command="echo" else cat_command="sudo cat" sed_command="sudo sed" echo_command="sudo echo" fi if [ "${check_file}" = "/etc/audit/auditd.conf" ] || [ "${check_file}" = "/etc/security/faillock.conf" ] || [ "${check_file}" = "/etc/security/pwquality.conf" ]; then spacer=" ${spacer} " fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else string="Value of \"${parameter_name}\" ${operator} set to \"${correct_value}\" in \"${check_file}\"" check_message "${string}" string="Parameter ${parameter_name} to ${correct_value} in ${check_file}" lock_message="Value of \"${parameter_name}\" to \"${correct_value}\" in \"${check_file}\"" if [ ! -f "${check_file}" ]; then if [ "${check_file}" = "/etc/default/sendmail" ] || [ "${check_file}" = "/etc/sysconfig/mail" ] || [ "${check_file}" = "/etc/rc.conf" ] || [ "${check_file}" = "/boot/loader.conf" ] || [ "${check_file}" = "/etc/sysconfig/boot" ] || [ "${check_file}" = "/etc/sudoers" ]; then line="${parameter_name}${separator}\"${correct_value}\"" else line="${parameter_name}${separator}${correct_value}" fi lock_command="echo '${line}' >> ${check_file}" if [ "${audit_mode}" = 1 ]; then inc_insecure "Parameter \"${parameter_name}\" ${negative} set to \"${correct_value}\" in \"${check_file}\"" fix_message "${lock_command}" else if [ "${audit_mode}" = 0 ]; then log_file="${restore_dir}/fileops.log" update_log "${log_file}" "rm,${check_file}" backup_file "${check_file}" if [ "${check_file}" = "/etc/system" ]; then reboot_required=1 notice_message "Reboot required" fi if [ "$sshd_test" = "1" ]; then notice_message "Service restart required for SSH" fi run_lockdown "${lock_command}" "${lock_message}" "sudo" fi if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " lineinfile:" echo " path: ${check_file}" echo " line: '${line}'" echo " create: yes" echo "" fi fi else correct_hyphen=$( echo "${correct_value}" | grep -c "^[\-]" | sed "s/ //g" ) if [ "${correct_hyphen}" = "1" ]; then correct_value="\\${correct_value}" fi param_hyphen=$( echo "${parameter_name}" | grep -c "^[\-]" | sed "s/ //g" ) if [ "${param_hyphen}" = "1" ]; then parameter_name="\\${parameter_name}" fi if [ "${separator}" = "tab" ]; then check_value=$( ${cat_command} "${check_file}" | grep -v "^${comment_value}" | grep "${parameter_name}" | awk '{print $2}' | sed 's/"//g' | uniq | grep -cE "${correct_value}" | sed "s/ //g" ) else if [ "$sshd_test" = "1" ]; then check_value=$( ${cat_command} "${check_file}" | grep -v "^${comment_value}" | grep "${parameter_name}" | cut -f2 -d"${separator}" | sed 's/"//g' | sed 's/ //g' | uniq | grep -cE "${correct_value}" | sed "s/ //g" ) if [ ! "${check_value}" ]; then check_value=$( ${cat_command} "${check_file}" | grep "${parameter_name}" | cut -f2 -d"${separator}" | sed 's/"//g' | sed 's/ //g' | uniq | grep -cE "${correct_value}" | sed "s/ //g" ) fi else if [ "${search_value}" ]; then if [ "${operator}" = "is" ]; then check_value=$( ${cat_command} "${check_file}" | grep -v "^${comment_value}" | grep "${parameter_name}" | cut -f2 -d"${separator}" | sed 's/"//g' | sed 's/ //g' | uniq | grep -cE "${search_value}" | sed "s/ //g" ) else check_value=$( ${cat_command} "${check_file}" | grep -v "^${comment_value}" | grep "${parameter_name}" | grep "${separator}" | uniq | grep -cE "${search_value}" | sed "s/ //g" ) fi else if [ "${operator}" = "is" ]; then check_value=$( ${cat_command} "${check_file}" | grep -v "^${comment_value}" | grep "${parameter_name}" | cut -f2 -d"${separator}" | sed 's/"//g' | sed 's/ //g' | uniq | grep -cE "${correct_value}" | sed "s/ //g" ) else check_value=$( ${cat_command} "${check_file}" | grep -v "^${comment_value}" | grep "${parameter_name}" | grep "${separator}" | uniq | grep -cE "${correct_value}" | sed "s/ //g" ) fi fi fi fi if [ "${operator}" = "is" ] || [ "${operator}" = "in" ]; then if [ "${check_value}" = "1" ]; then test_value=1 else test_value=0 fi else if [ "${check_value}" = "" ]; then test_value=0 else test_value=1 fi fi if [ "${ansible_mode}" = 1 ]; then if [ "${negative}" = "not" ]; then line="${parameter_name}${separator}${correct_value}" else line="${comment_value}${parameter_name}${separator}${correct_value}" fi echo "" echo "- name: ${string}" echo " lineinfile:" echo " path: ${check_file}" echo " . regex: '^${parameter_name}'" echo " line: '${line}'" echo "" fi if [ "${separator}" = "tab" ]; then check_parameter=$( ${cat_command} "${check_file}" | grep -v "^${comment_value}" | grep "${parameter_name}" | awk '{print $1}' ) else check_parameter=$( ${cat_command} "${check_file}" | grep -v "^${comment_value}" | grep "${parameter_name}" | cut -f1 -d"${separator}" | sed 's/ //g' | uniq ) fi if [ "$test_value" = 0 ]; then correct_hyphen=$( echo "${correct_value}" | grep -c "^[\\]" | sed "s/ //g" ) if [ "${correct_hyphen}" = "1" ]; then correct_value=$( echo "${correct_value}" | sed "s/^[\\]//g" ) fi param_hyphen=$( echo "${parameter_name}" | grep -c "^[\\]" | sed "s/ //g" ) if [ "${param_hyphen}" = "1" ]; then parameter_name=$( echo "${parameter_name}" | sed "s/^[\\]//g" ) fi if [ "${audit_mode}" = 1 ]; then inc_insecure "Parameter \"${parameter_name}\" ${negative} set to \"${correct_value}\" in \"${check_file}\"" if [ "${check_parameter}" != "${parameter_name}" ]; then if [ "${separator}" = "tab" ]; then fix_message "echo -e \"${parameter_name}\t${correct_value}\" >> ${check_file}" else if [ "${position}" = "after" ]; then fix_message "${cat_command} ${check_file} | sed \"s,${search_value},&\\\n${parameter_name}${separator}${correct_value},\" > ${temp_file}" fix_message "${cat_command} ${temp_file} > ${check_file}" else fix_message "echo \"${parameter_name}${separator}${correct_value}\" >> ${check_file}" fi fi else if [ "${check_file}" = "/etc/default/sendmail" ] || [ "${check_file}" = "/etc/sysconfig/mail" ] || [ "${check_file}" = "/etc/rc.conf" ] || [ "${check_file}" = "/boot/loader.conf" ] || [ "${check_file}" = "/etc/sysconfig/boot" ] || [ "${check_file}" = "/etc/sudoers" ]; then fix_message "${sed_command} \"s/^${parameter_name}.*/${parameter_name}${spacer}\"${correct_value}\"/\" ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" else fix_message "${sed_command} \"s/^${parameter_name}.*/${parameter_name}${spacer}${correct_value}/\" ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" fi fi else if [ "${audit_mode}" = 0 ]; then set_message "Parameter \"${parameter_name}\" to \"${correct_value}\" in \"${check_file}\"" if [ "${check_file}" = "/etc/system" ]; then reboot_required=1 notice_message "Reboot required" fi if [ "${check_file}" = "/etc/ssh/sshd_config" ] || [ "${check_file}" = "/etc/sshd_config" ]; then notice_message "Service restart required for SSH" fi backup_file "${check_file}" if [ "${check_parameter}" != "${parameter_name}" ]; then if [ "${separator_value}" = "tab" ]; then lock_command="${echo_command} -e \"${parameter_name}\t${correct_value}\" >> ${check_file}" else if [ "${position}" = "after" ]; then lock_command="${cat_command} ${check_file} | sed \"s,${search_value},&\\\n${parameter_name}${separator}${correct_value},\" > ${temp_file} ; ${cat_command} ${temp_file} > ${check_file} ; rm ${temp_file}" else lock_command="${echo_command} \"${parameter_name}${separator}${correct_value}\" >> ${check_file}" fi fi run_lockdown "${lock_command}" "${lock_message}" "sudo" else if [ "${check_file}" = "/etc/default/sendmail" ] || [ "${check_file}" = "/etc/sysconfig/mail" ] || [ "${check_file}" = "/etc/rc.conf" ] || [ "${check_file}" = "/boot/loader.conf" ] || [ "${check_file}" = "/etc/sysconfig/boot" ] || [ "${check_file}" = "/etc/sudoers" ]; then lock_command="${sed_command} \"s/^${parameter_name}.*/${parameter_name}${spacer}\\"${correct_value}\\"/\" ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" else lock_command="${sed_command} \"s/^${parameter_name}.*/${parameter_name}${spacer}${correct_value}/\" ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" fi run_lockdown "${lock_command}" "${lock_message}" "sudo" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" != "11" ]; then pkgchk -f -n -p "${check_file}" 2> /dev/null else pkg fix $( pkg search "${check_file}" | grep pkg | awk '{print $4}' ) fi fi fi fi fi else inc_secure "Parameter \"${parameter_name}\" ${operator} set to \"${correct_value}\" in \"${check_file}\"" fi fi fi fi } check_file_value () { if [ -n "${7}" ]; then check_file_value_with_position "${1}" "${2}" "${3}" "${4}" "${5}" "${6}" "${7}" "" else if [ -n "${8}" ]; then check_file_value_with_position "${1}" "${2}" "${3}" "${4}" "${5}" "${6}" "${7}" "${8}" else check_file_value_with_position "${1}" "${2}" "${3}" "${4}" "${5}" "${6}" "" "" fi fi } ================================================ FILE: functions/file/disable_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # disable_value # # Code to comment out a line # # This routine takes 3 values # check_file = Name of file to check # parameter_name = Line to comment out # comment_value = The character to use as a comment, eg # (passed as hash) #. disable_value () { check_file="${1}" parameter_name="${2}" comment_value="${3}" print_function "disable_value" if [ -f "${check_file}" ]; then if [ "${comment_value}" = "star" ]; then comment_value="*" else if [ "${comment_value}" = "bang" ]; then comment_value="!" else comment_value="#" fi fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else check_message "Parameter \"${parameter_name}\" in \"${check_file}\" is disabled" if [ "${separator}" = "tab" ]; then param_hyphen=$( echo "${parameter_name}" | grep "^[\-]" ) if [ "${param_hyphen}" ]; then parameter_name="\\${parameter_name}" fi check_value=$( grep -v "^${comment_value}" "${check_file}" | grep "${parameter_name}" | uniq ) param_hyphen=$( echo "${parameter_name}" | grep "^[\\]" ) if [ "${param_hyphen}" ]; then parameter_name=$( echo "${parameter_name}" | sed "s/^[\\]//g" ) fi if [ "${check_value}" != "${parameter_name}" ]; then inc_insecure "Parameter \"${parameter_name}\" not set to \"${correct_value}\" in ${check_file}" if [ "${audit_mode}" = 0 ]; then set_message "Parameter \"${parameter_name}\" to \"${correct_value}\" in ${check_file}" if [ "${check_file}" = "/etc/system" ]; then reboot_required=1 notice_message "Reboot required" fi if [ "${check_file}" = "/etc/ssh/sshd_config" ] || [ "${check_file}" = "/etc/sshd_config" ]; then notice_message "Service restart required SSH" fi backup_file "${check_file}" sed "s/${parameter_name}/${comment_value}&" < "${check_file}" > "${temp_file}" cat "${temp_file}" > "${check_file}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" != "11" ]; then pkgchk -f -n -p "${check_file}" 2> /dev/null else pkg_info=$( pkg search "${check_file}" | grep pkg | awk '{print $4}' ) pkg fix "${pkg_info}" fi fi rm "${temp_file}" fi fi else inc_secure "Parameter \"${parameter_name}\" already set to \"${correct_value}\" in ${check_file}" fi fi fi } ================================================ FILE: functions/file/replace_file_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # replace_file_value # # Replace a value in a file with the correct value # # As there is no interactive sed on Solaris, ie sed -i # pipe through sed to a temporary file, then replace original file # Some handling is added to replace / when searching so sed works # # check_file = File to replace value in # check_value = Value to check for # correct_value = What the value should be # position = Position of value in the line #. replace_file_value () { check_file="${1}" check_value="${2}" new_check_value="${check_value}" correct_value="${3}" new_correct_value="${correct_value}" position="${4}" print_function "replace_file_value" if [ "${position}" = "start" ]; then position="^" else position="" fi string_check=$( expr "${check_value}" : "\/" ) if [ "${string_check}" = 1 ]; then new_check_value=$( echo "${check_value}" | sed 's,/,\\\/,g' ) fi string_check=$( expr "${correct_value}" : "\/" ) if [ "${string_check}" = 1 ]; then new_correct_value=$( echo "${correct_value}" | sed 's,/,\\\/,g' ) fi new_check_value="${position}${new_check_value}" if [ "${audit_mode}" != 2 ]; then string="File \"${check_file}\" contains \"${correct_value}\" rather than \"${check_value}\"" check_message "${string}" fi if [ -f "${check_file}" ]; then check_dfs=$( grep -c "${new_check_value}" < "${check_file}" | sed "s/ //g" ) fi if [ "${check_dfs}" != 0 ]; then if [ "${audit_mode}" != 2 ]; then if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " lineinfile:" echo " path: ${check_file}" echo " regexp: '${new_check_value}" echo " replace: '${new_correct_value}" echo "" fi inc_insecure "File \"${check_file}\" contains \"${check_value}\" rather than \"${correct_value}\"" backup_file "${check_file}" lock_command="sed -e \"s/${new_check_value}/${new_correct_value}/\" < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" run_lockdown "${lock_command}" "Share entries in ${check_file} to be secure" "sudo" if [ "${os_version}" != "11" ]; then pkgchk -f -n -p "${check_file}" 2> /dev/null else pkg_info=$( pkg search "${check_file}" | grep pkg | awk '{print $4}' ) pkg fix "${pkg_info}" fi else restore_file "${check_file}" "${restore_dir}" fi else inc_secure "File ${check_file} contains \"${correct_value}\" rather than \"${check_value}\"" fi } ================================================ FILE: functions/file/restore_file.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # restore_file # # Restore file # # This routine restores a file from the backup directory to its original # As par of the restore it also restores the original permissions # # check_file = The name of the original file # restore_dir = The directory to restore from #. restore_file () { check_file="${1}" check_dir="${2}" print_function "restore_file" if [ ! "${check_dir}" ]; then restore_file="${restore_dir}${check_file}" else restore_file="${check_dir}${check_file}" fi log_file="${restore_dir}/fileops.log" if [ "${audit_mode}" = 2 ]; then if [ -f "${restore_file}" ]; then if [ -f "${log_file}" ]; then operation=$( grep "${check_file}" < "${log_file}" | cut -f1 -d, ) if [ -n "${operation}" ]; then restore_command="${operation} \"${check_file}\"" restore_message="${restore_command}" execute_restore "${restore_message}" "${restore_command}" "sudo" fi else sum_check_file=$( cksum "${check_file}" | awk '{print $1}' ) sum_restore_file=$( cksum "${restore_file}" | awk '{print $1}' ) if [ "$sum_check_file" != "$sum_restore_file" ]; then restore_message="File \"${restore_file}\" to \"${check_file}\"" restore_command="cp -p \"${restore_file}\" \"${check_file}\"" execute_restore "${restore_message}" "${restore_command}" "sudo" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" != "11" ]; then pkgchk -f -n -p "${check_file}" 2> /dev/null else pkg_info=$( pkg search "${check_file}" | grep pkg | awk '{print $4}' ) pkg fix "${pkg_info}" fi fi fi fi if [ "${check_file}" = "/etc/system" ]; then reboot_required=1 verbose_message "Reboot required" "notice" fi check_base=$( basename "${check_file}" ) if [ "${check_base}" = "sshd_config" ]; then verbose_message "Notice: Service restart required for SSH" fi if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Restart ssh service" echo " service:" echo " name: ssh" echo " state: restarted" echo "" fi else if [ -f "${log_file}" ]; then operation=$( grep "${check_file}" < "${log_file}" | cut -f1 -d, ) if [ -n "${operation}" ]; then restore_command="${operation} \"${check_file}\"" restore_message="${restore_command}" execute_restore "${restore_message}" "${restore_command}" "sudo" fi fi fi fi } ================================================ FILE: functions/file/update_log_file.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # update_log # # Update log file # # log_file = The name of the original file # log_vale = The directory to restore from #. update_log () { log_file="${1}" log_value="${2}" print_function "update_log" log_dir=$( dirname "${log_file}" ) if [ "${log_dir}" = "." ]; then log_file="${restore_dir}/${log_file}" fi if [ "${audit_mode}" = "0" ]; then echo "${log_value}" >> "${log_file}" fi } ================================================ FILE: functions/kubernetes/audit_kubernetes.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kubernetes_all # # Audit Kubernetes # # All the Kubernetes specific tests #. audit_kubernetes_all () { print_function "audit_kubernetes_all" audit_kubernetes_apiserver audit_kubernetes_scheduler audit_kubernetes_controller audit_kubernetes_etcd audit_kubernetes_kubelet } # funct_audit_kubernetes # # Audit Kubernetes #. funct_audit_kubernetes () { audit_mode="${1}" print_function "funct_audit_kubernetes" audit_kubernetes_all print_results } ================================================ FILE: functions/linux/check_ausearch.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_ausearch # # Check what the auditing entries are for a specific command #. check_ausearch () { if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then funct="${1}" bin="${2}" command="${3}" mode="${4}" value="${5}" print_function "check_ausearch" exists=$( command -v "${bin}" ) if [ "${exists}" ]; then if [ "${value}" ]; then check=$( ausearch -k "${bin}" 2> /dev/null | grep "${command}" | grep "${mode}" | grep "${value}" ) secure_string="Binary \"${bin}\" has commands \"${command}\" with option \"${mode}\" is set to \"${value}\"" insecure_string="Binary \"${bin}\" has commands \"${command}\" with option \"${mode}\" is not set to \"${value}\"" else check=$( ausearch -k "${bin}" 2> /dev/null | grep "${command}" | grep "${mode}" ) secure_string="Binary \"${bin}\" has commands \"${command}\" with option \"${mode}\" is set" insecure_string="Binary \"${bin}\" has commands \"${command}\" with option \"${mode}\" is unset" fi check_message "${secure_string}" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${secure_string}" echo " file:" echo " path: ${check_file}" echo " mode: ${check_perms}" echo "" fi if [ "$funct" = "equal" ]; then if [ "${value}" ]; then if [ -z "${check}" ]; then inc_insecure "${insecure_string}" else inc_secure "${secure_string}" fi else if [ "${check}" ]; then inc_insecure "${insecure_string}" else inc_secure "${secure_string}" fi fi else if [ "${value}" ]; then if [ "${check}" ]; then inc_insecure "${insecure_string}" else inc_secure "${secure_string}" fi else if [ -z "${check}" ]; then inc_insecure "${insecure_string}" else inc_secure "${secure_string}" fi fi fi fi fi fi } ================================================ FILE: functions/linux/check_chkconfig_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_chkconfig_service # # Code to audit a service managed by chkconfig, and enable, or disbale # # service_name = Name of service # service_level = Level service runs at # correct_status = What the status of the service should be, ie enabled/disabled #. check_chkconfig_service () { if [ "${os_name}" = "VMkernel" ]; then service_name="${1}" service_level="${2}" correct_status="${3}" print_function "check_chkconfig_service" chk_config="/bin/chkconfig" log_file="chkconfig.log" actual_status=$( ${chk_config} --list "${service_name}" | awk '{print $2}' ) if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then check_status=$( grep "${service_name}" "${restore_file}" | cut -f2 -d, ) if [ "${check_status}" = "on" ] || [ "${check_status}" = "off" ]; then if [ "${check_status}" != "${actual_status}" ]; then restore_command="${chk_config} --level ${service_level} ${service_name} ${check_status}" restore_message="Restoring: Service \"${service_name}\" at run level \"${service_level}\" to \"${check_status}\"" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi else if [ "${actual_status}" = "on" ] || [ "${actual_status}" = "off" ]; then string="Service \"${service_name}\" is \"${correct_status}\"" check_message "${string}" if [ "${actual_status}" != "${correct_status}" ]; then inc_insecure "Service \"${service_name}\" is not \"${correct_status}\"" update_log "${log_file}" "${service_name},${actual_status}" lock_command="${chk_config} ${service_name} ${correct_status}" lock_message="Service \"${service_name}\" to \"${correct_status}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "${string}" fi fi fi fi if [ "${os_name}" = "Linux" ]; then service_name="${1}" service_level="${2}" correct_status="${3}" secure_string="Sevice \"${service_name}\" at run level \"${service_level}\" at rune level \"${service_level}\" is \"${correct_status}\"" insecure_string="Service \"${service_name}\" at run level \"${service_level}\" at rune level \"${service_level}\" is \"${correct_status}\"" check_message "${secure_string}" if [ "${correct_status}" = "on" ]; then enabled="yes" else enabled="no" fi if [ "${linux_dist}" = "debian" ]; then chk_config="/usr/sbin/sysv-rc-conf" else chk_config="/usr/sbin/chkconfig" if [ ! -f "${chk_config}" ]; then chk_config="/sbin/chkconfig" fi fi log_file="chkconfig.log" if [ "${service_level}" = "3" ]; then actual_status=$( ${chk_config} --list "${service_name}" 2> /dev/null | awk '{print $5}' | cut -f2 -d':' | awk '{print $1}' ) fi if [ "${service_level}" = "5" ]; then actual_status=$( ${chk_config} --list "${service_name}" 2> /dev/null | awk '{print $7}' | cut -f2 -d':' | awk '{print $1}' ) fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then check_status=$( grep "${service_name}" "${restore_file}" | grep ",${service_level}," | cut -f3 -d, ) if [ "${check_status}" = "on" ] || [ "${check_status}" = "off" ]; then if [ "${check_status}" != "${actual_status}" ]; then restore_command="${chk_config} --level ${service_level} ${service_name} ${check_status}" restore_message="Restoring: Service \"${service_name}\" at run level \"${service_level}\" to \"${check_status}\"" execute_restore "${restore_command}" "${restore_message}" fi fi fi else if [ "${actual_status}" = "on" ] || [ "${actual_status}" = "off" ]; then if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " service:" echo " name: ${service_name}" echo " enabled: ${enabled}" echo "" fi if [ "${actual_status}" != "${correct_status}" ]; then inc_insecure "${insecure_string}" update_log "${log_file}" "${service_name},${service_level},${actual_status}" lock_command="${chk_config} --level ${service_level} ${service_name} ${correct_status}" lock_message="Service ${service_name} at run level ${service_level} to ${correct_status}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "${secure_string}" fi fi fi fi } ================================================ FILE: functions/linux/check_debian_package.sh ================================================ #!/bin/sh # -> Needs checking for install_check # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_debian_package # # Check if a deb is installed, if so install_check will be be set with name of dep, # otherwise it will be empty #. check_debian_package () { package_name="${1}" print_function "check_debian_package" check_message "Debian package \"${package_name}\"" install_check=$( dpkg -l "${package_name}" 2>&1 | grep "${package_name}" | awk '{print $2}' | grep "^${package_name}$" ) } ================================================ FILE: functions/linux/check_gsettings_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_gsettings_value # # Audit gsettings values # # This routine takes the followinf values # # parameter_root = The parameter root to be checked # parameter_name = The parameter name to be checked # correct_value = The value we expect to be returned # # If the current_value is not the correct_value then it is fixed if run in lockdown mode # A copy of the value is stored in a log file, which can be restored #. check_gsettings_value () { parameter_root="${1}" parameter_name="${2}" correct_value="${3}" print_function "check_gsettings_value" command_name="gsettings" log_file="${command_name}.log" check=$( command -v gsettings 2> /dev/null | wc -l | sed "s/ //g" ) if [ "${check}" = "1" ]; then string="Parameter \"${parameter_name}\" to \"${correct_value}\"" check_message "${string}" set_command="gsettings set" get_command="gsettings get" if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then parameter_root=$( grep "${parameter_name}" "${restore_file}" | cut -f1 -d',' ) parameter_name=$( grep "${parameter_name}" "${restore_file}" | cut -f2 -d',' ) correct_value=$( grep "${parameter_name}" "${restore_file}" | cut -f3 -d',' ) package_test=$( echo "${parameter_name}" | grep "[A-z]" ) if [ -n "${package_test}" ]; then restore_message="Parameter \"${parameter_name}\" to \"${correct_value}\"" restore_command="${set_command} ${parameter_root} ${parameter_name} ${correct_value}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi else value_check=$( gsettings get "${parameter_root}" "${parameter_name}" 2> /dev/null | grep -c "${correct_value}" | sed "s/ //g" ) if [ "${value_check}" = "0" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Parameter \"${parameter_name}\" is not set to \"${correct_value}\" in ${parameter_root}" string="Parameter \"${parameter_root}.${parameter_name}\" to \"${correct_value}\"" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Setting ${string}" echo " gsetting:" echo " ${parameter_root}.${parameter_name}: ${correct_value}" echo "" fi fix_message "${set_command} ${parameter_root} ${parameter_name} \"${correct_value}\"" else current_value=$( gsettings get "${parameter_root}" "${parameter_name}" 2> /dev/null ) if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${parameter_root},${parameter_name},${current_value}" lock_message="Parameter \"${parameter_name}\" to \"${correct_value}\"" lock_command="${set_command} ${parameter_root} ${parameter_name} ${correct_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Parameter \"${parameter_name}\" is set to \"${correct_value}\" in ${parameter_root}" fi fi fi fi fi } ================================================ FILE: functions/linux/check_linux_package.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_linux_package # # Check package # Takes the following variables: # package_mode: Mode, eg check install uninstall restore # package_check: Package to check for #. check_linux_package_with_group () { if [ "${os_name}" = "Linux" ]; then package_mode="${1}" package_check="${2}" group_check="${3}" print_function "check_linux_package_with_group" package_type="Package" if [ "${package_mode}" = "install" ]; then package_status="installed" package_state="present" else package_status="uninstalled" package_state="absent" fi log_file="package_log" if [ "${audit_mode}" != "2" ]; then string="${package_type} \"${package_check}\" is \"${package_status}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: ${string}" echo " package:" echo " name: ${package_check}" echo " state: $package_state" echo "" fi if [ "${linux_dist}" = "debian" ]; then package_name=$( dpkg -l "${package_check}" 2>&1 | grep "${package_check}" | awk '{print $2}' ) else if [ "${linux_dist}" = "arch" ]; then package_name=$( pacman -Qi "${package_check}" 2>&1 | grep '^Name' | awk '{print $3}' ) else if [ ! "${group_check}" = "" ]; then package_type="Group" package_name=$( yum grouplist 2>&1 | grep "${package_check}" | sed "s/^ //g" ) else package_name=$( rpm -qi "${package_check}" | grep '^Name' | awk '{print $3}' ) fi fi fi if [ "${package_mode}" = "install" ] && [ "${package_name}" = "${package_check}" ]; then inc_secure "${package_type} \"${package_check}\" is \"${package_status}\"" else if [ "${package_mode}" = "uninstall" ] && [ "${package_name}" != "${package_check}" ] || [ "${package_name}" = "" ]; then inc_secure "${package_type} \"${package_check}\" is \"${package_status}\"" else inc_insecure "${package_type} \"${package_check}\" is not \"${package_status}\"" fi fi if [ "${package_mode}" = "install" ]; then if [ "${linux_dist}" = "redhat" ]; then if [ "${group_check}" ]; then package_command="yum -y groupinstall ${package_check}" else package_command="yum -y install ${package_check}" fi fi if [ "${linux_dist}" = "suse" ]; then package_command="zypper install ${package_check}" fi if [ "${linux_dist}" = "debian" ]; then package_command="apt-get install ${package_check}" fi if [ "${linux_dist}" = "arch" ]; then package_command="pacman -S ${package_check}" fi if [ "${package_check}" = "aide" ]; then if [ -f "/usr/sbin/aide" ]; then if [ ! -f "/var/lib/aide/aide.db.gz" ]; then /usr/sbin/aide --init -B "database_out=file:/var/lib/aide/aide.db.gz" fi fi fi fi if [ "${package_mode}" = "uninstall" ]; then if [ "${linux_dist}" = "redhat" ]; then if [ "${group_check}" ]; then package_command="yum -y groupremove ${package_check}" else package_command="rpm -e ${package_check}" fi fi if [ "${linux_dist}" = "suse" ]; then package_command="zypper remove ${package_check}" fi if [ "${linux_dist}" = "debian" ]; then package_command="apt-get purge ${package_check}" fi if [ "${linux_dist}" = "arch" ]; then package_command="pacman -R ${package_check}" fi fi lock_message="${package_type} \"${package_check}\" to \"${package_status}\"" if [ "${audit_mode}" = "0" ] && [ "${package_mode}" != "check" ]; then if [ "$package_uninstall" = "yes" ]; then update_log "${log_file}" "${package_check},${package_mode}" lock_command="${package_command}" run_lockdown "${lock_command}" "${lock_message}" else inc_insecure "Not uninstalling package as package uninstall has been set to no" fix_message "${package_command}" fi else fix_message "${package_command}" fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then restore_check=$( grep "${package_check}" "${restore_file}" | awk '{print $2}' ) if [ "$restore_check" = "${package_check}" ]; then package_action=$( grep "${package_check}" "${restore_file}" | awk '{print $1}' ) restore_message="Package \"${package_check}\" to\" ${package_action}\"" if [ "${package_action}" = "install" ]; then if [ "${linux_dist}" = "redhat" ]; then if [ "${group_check}" ]; then restore_command="yum groupremove ${package_check}" else restore_command="rpm -e ${package_check}" fi fi if [ "${linux_dist}" = "debian" ]; then restore_command="apt-get purge ${package_check}" fi if [ "${linux_dist}" = "suse" ]; then restore_command="zypper remove ${package_check}" fi if [ "${linux_dist}" = "arch" ]; then restore_command="pacman -R ${package_check}" fi else if [ "${linux_dist}" = "redhat" ]; then if [ "${group_check}" ]; then restore_command="yum groupinstall ${package_check}" else restore_command="yum -y install ${package_check}" fi fi if [ "${linux_dist}" = "debian" ]; then restore_command="apt-get install ${package_check}" fi if [ "${linux_dist}" = "suse" ]; then restore_command="zypper install ${package_check}" fi if [ "${linux_dist}" = "arch" ]; then restore_command="pacman -S ${package_check}" fi fi execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi fi } check_linux_package () { check_linux_package_with_group "${1}" "${2}" "" } ================================================ FILE: functions/linux/check_linux_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_linux_service # # Code to audit a linux service managed by chkconfig, and enable, or disable # # service_name = Name of service # correct_status = What the status of the service should be, ie enabled/disabled #. check_linux_service () { service_name="${1}" correct_status="${2}" print_function "check_linux_service" if [ "${os_name}" = "VMkernel" ] || [ "${os_name}" = "Linux" ]; then if [ -f "/usr/bin/systemctl" ]; then if [ "${correct_status}" = "on" ] || [ "${correct_status}" = "enable" ]; then correct_status="enable" else correct_status="disable" fi check_systemctl_service "${correct_status}" "${service_name}" else check_chkconfig_service "${service_name}" "3" "${correct_status}" check_chkconfig_service "${service_name}" "5" "${correct_status}" fi fi } ================================================ FILE: functions/linux/check_systemctl_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_systemctl_service # # Code to audit a service managed by systemctl, and enable, or disable # # service_name = Name of service # service_level = Level service runs at # correct_status = What the status of the service should be, ie enabled/disabled #. check_systemctl_service () { temp_status="${1}" temp_name="${2}" print_function "check_systemctl_service" use_systemctl="no" if [ "${temp_name}" = "on" ] || [ "${temp_name}" = "off" ]; then correct_status="${temp_name}" service_name="${temp_status}" else correct_status="${temp_status}" service_name="${temp_name}" fi if [ "${correct_status}" = "enable" ] || [ "${correct_status}" = "enabled" ] || [ "${correct_status}" = "on" ]; then service_switch="enable" correct_status="enabled" else service_switch="disable" correct_status="disabled" fi if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 16 ]; then use_systemctl="yes" fi if [ "${os_vendor}" = "Centos" ] || [ "${os_vendor}" = "Red" ] && [ "${os_version}" -ge 7 ]; then use_systemctl="yes" fi fi if [ "${correct_status}" = "disabled" ]; then search_string="disabled" else search_string="enabled" fi if [ "${use_systemctl}" = "yes" ]; then log_file="systemctl.log" alias_check=$( systemctl is-enabled "${service_name}" 2> /dev/null | grep -c "alias" | sed "s/ //g" ) if [ "$alias_check" = "1" ]; then service_name=$( systemctl status "${service_name}" 2> /dev/null | head -1 | awk '{print $2}' ) fi nf_status=$( systemctl is-enabled "${service_name}" 2> /dev/null | grep -c "not-found" | sed "s/ //g" ) if [ "$nf_status" = "1" ]; then actual_status="not-found" else en_status=$( systemctl is-enabled "${service_name}" 2> /dev/null | grep -cE "enabled|static" | sed "s/ //g" ) if [ "$en_status" = "1" ]; then actual_status="enabled" else en_status=$( systemctl is-enabled "${service_name}" 2> /dev/null | grep -cE "disabled" | sed "s/ //g" ) if [ "$en_status" = "1" ]; then actual_status="disabled" fi fi fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then check_status=$( grep "${service_name}" "${restore_file}" | cut -f2 -d, ) if [ "${check_status}" = "enabled" ] || [ "${check_status}" = "disabled" ]; then if [ "${check_status}" != "${actual_status}" ]; then verbose_message "Restoring: Service ${service_name} at run level ${service_level} to ${check_status}" if [ "${check_status}" = "enable" ] || [ "${check_status}" = "enabled" ]; then service_switch="enable" else service_switch="disable" fi eval "systemctl ${service_switch} ${service_name} 2> /dev/null" fi fi fi else string="Service \"${service_name}\" is \"${correct_status}\"" check_message "${string}" if [ "${audit_mode}" != 2 ]; then if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " service:" echo " name: ${service_name}" echo " enabled: ${enabled}" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" fi fi if [ "${actual_status}" = "is-enabled" ] || [ "${actual_status}" = "disabled" ] || [ "${actual_status}" = "not-found" ] || [ "${actual_status}" = "enabled" ]; then if [ "${correct_status}" = "enabled" ] && [ "${actual_status}" = "not-found" ]; then inc_insecure "Service \"${service_name}\" is \"${actual_status}\"" else if [ "${actual_status}" != "${correct_status}" ] && [ ! "${actual_status}" = "not-found" ]; then inc_insecure "Service \"${service_name}\" is not \"${correct_status}\"" update_log "${log_file}" "${service_name},${actual_status}" lock_command="systemctl ${service_switch} ${service_name} 2> /dev/null" lock_message="Service \"${service_name}\" to \"${correct_status}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" else if [ "${actual_status}" = "not-found" ]; then inc_secure "Service \"${service_name}\" is \"${actual_status}\"" else inc_secure "Service \"${service_name}\" is \"${correct_status}\"" fi fi fi fi fi fi } ================================================ FILE: functions/linux/check_xinetd_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_xinetd_service # # Code to audit an xinetd service, and enable, or disable # # service_name = Name of service # correct_status = What the status of the service should be, ie enabled/disabled #. audit_xinetd_service () { if [ "${os_name}" = "Linux" ]; then service_name="${1}" parameter_name="${2}" correct_status="${3}" print_function "audit_xinetd_service" check_file="/etc/xinetd.d/${service_name}" log_file="${work_dir}/${service_name}.log" if [ -f "${check_file}" ]; then actual_status=$( grep "${parameter_name}" "${check_file}" | awk '{print $3}' ) if [ "${audit_mode}" != 2 ]; then string="If xinetd service \"${service_name}\" has \"${parameter_name}\" set to \"${correct_status}\"" check_message "${string}" if [ "${actual_status}" != "${correct_status}" ]; then if [ "${linux_dist}" = "debian" ]; then command="update-rc.d ${service_name} ${correct_status}" else command="chkconfig ${service_name} ${correct_status}" fi inc_insecure "Service \"${service_name}\" does not have \"${parameter_name}\" set to \"${correct_status}\"" lock_command="${check_file} |sed 's/${parameter_name}.*/${parameter_name} = ${correct_status}/g' > ${temp_file} ; cat ${temp_file} > ${check_file} ; ${command}" backup_file "${check_file}" update_log "${log_file}" "${parameter_name},${actual_status}" run_lockdown "${lock_command}" "Service to ${parameter_name}" "sudo" else inc_secure "Service \"${service_name}\" has \"${parameter_name}\" set to \"${correct_status}\"" fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_xinetd_service_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"cat ${check_file} |grep ${parameter_name} |awk '{print \$3}'\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${lock_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then check_name=$( grep "${service_name}" "${restore_file}" | cut -f1 -d, ) if [ "$check_name" = "${service_name}" ]; then check_status=$( grep "${service_name}" "${restore_file}" | cut -f2 -d, ) if [ "${actual_status}" != "${check_status}" ]; then restore_file "${check_file}" "${restore_dir}" fi fi fi fi fi fi } ================================================ FILE: functions/packages/check_package.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_package # # Check Package #. check_package () { package_name="${1}" print_function "check_package" if [ "${os_name}" = "Linux" ]; then check_linux_package "${package_name}" fi if [ "${os_name}" = "SunOS" ]; then check_solaris_package "${package_name}" fi } ================================================ FILE: functions/services/check_inetd_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2028 # check_inetd_service # # Change status of an inetd (/etc/inetd.conf) services # #. check_inetd_service () { if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then service_name="${1}" correct_status="${2}" print_function "check_inetd_service" check_file="/etc/inetd.conf" log_file="${service_name}.log" if [ -f "${check_file}" ]; then if [ "${correct_status}" = "disabled" ]; then actual_status=$( grep "^${service_name}" "${check_file}" | grep -v '^#' | awk '{print $1}' ) else actual_status=$( grep "^${service_name}" "${check_file}" | awk '{print $1}' ) fi if [ "${audit_mode}" != 2 ]; then string="If inetd service \"${service_name}\" is set to \"${correct_status}\"" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " lineinfile:" echo " path: ${check_file}" echo " regexp: ''(.*${service_name}.*)'" echo " replace: '#\1'" echo " when: ansible_facts['ansible_system'] == '${os_name}' or ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${actual_status}" != "" ]; then inc_insecure "Service \"${service_name}\" does not have \"${parameter_name}\" set to \"${correct_status}\"" backup_file "${check_file}" if [ "${correct_status}" = "disable" ]; then disable_value "${check_file}" "${service_name}" "hash" else : fi else inc_secure "Service \"${service_name}\" is set to \"${correct_status}\"" fi else restore_file "${check_file}" "${restore_dir}" fi fi fi } ================================================ FILE: functions/sunos/audit_system.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # funct_audit_system # # Audit System #. funct_audit_system () { audit_mode="${1}" print_function "funct_audit_system" if [ "${audit_mode}" = 0 ]; then if [ ! -d "${work_dir}" ]; then mkdir -p "${work_dir}" if [ "${os_name}" = "SunOS" ]; then echo "Creating: Alternate Boot Environment ${date_suffix}" if [ "${os_version}" = "11" ]; then beadm create "audit_${date_suffix}" fi if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then if [ "${os_platform}" != "i386" ]; then lucreate -n "audit_${date_suffix}" fi fi else : # Add code to do LVM snapshot fi fi fi if [ "${audit_mode}" = 2 ]; then restore_dir="${base_dir}/${restore_date}" if [ ! -d "${restore_dir}" ]; then echo "Restore directory \"${restore_dir}\" does not exit" exit else set_message "Restore directory to \"${restore_dir}\"" fi fi audit_system_all if [ "${do_fs}" = 1 ]; then audit_search_fs fi #audit_test_subset sparc_test=$( echo "${os_platform}" | grep -c "sparc" | sed "s/ //g" ) if [ "${sparc_test}" = "0" ]; then audit_system_x86 else audit_system_sparc fi print_results } # audit_system_all # # Audit All System #. audit_system_all () { print_function "audit_system_all" full_audit_shell_services full_audit_accounting_services full_audit_firewall_services full_audit_password_services full_audit_kernel_services full_audit_mail_services full_audit_user_services full_audit_disk_services full_audit_hardware_services full_audit_power_services full_audit_virtualisation_services full_audit_x11_services full_audit_naming_services full_audit_file_services full_audit_web_services full_audit_print_services full_audit_routing_services full_audit_windows_services full_audit_other_daemons full_audit_log_services full_audit_network_services full_audit_other_services full_audit_update_services if [ "${os_name}" = "Darwin" ]; then full_audit_osx_services fi } ================================================ FILE: functions/sunos/audit_system_sparc.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_sparc # # Audit SPARC #. audit_system_sparc () { print_function "audit_system_sparc" if [ "${os_name}" = "SunOS" ]; then audit_eeprom_security fi } ================================================ FILE: functions/sunos/audit_system_x86.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_x86 # # Audit x86 #. audit_system_x86 () { print_function "audit_system_x86" if [ "${os_name}" = "SunOS" ]; then audit_grub_security audit_kdm_config fi } ================================================ FILE: functions/sunos/check_initd_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2010 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_initd_service # # Code to audit an init.d service, and enable, or disable service # # service_name = Name of service # correct_status = What the status of the service should be, ie enabled/disabled #. check_initd_service () { if [ "${os_name}" = "SunOS" ]; then service_name="${1}" correct_status="${2}" print_function "check_initd_service" log_file="initd.log" service_check=$( ls /etc/init.d | grep "^${service_name}$" | sed 's/ //g' ) if [ -n "${service_check}" ]; then if [ "${correct_status}" = "disabled" ]; then check_file="/etc/init.d/_${service_name}" if [ -f "${check_file}" ]; then actual_status="disabled" else actual_status="enabled" fi else check_file="/etc/init.d/${service_name}" if [ -f "${check_file}" ]; then actual_status="enabled" else actual_status="disabled" fi fi if [ "${audit_mode}" != 2 ]; then string="If init.d service \"${service_name}\" is \"${correct_status}\"" verbose_message " ${string}" "check" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " service:" echo " name: ${service_name}" echo " enabled: ${actual_status}" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" fi fi if [ "${actual_status}" != "${correct_status}" ]; then inc_insecure "Service \"${service_name}\" is not \"${correct_status}\"" update_log "${log_file}" "${service_name},${actual_status}" lock_message="Service ${service_name} to ${correct_status}" if [ "${correct_status}" = "disabled" ]; then lock_command="/etc/init.d/${service_name} stop ; mv /etc/init.d/${service_name} /etc/init.d/_${service_name}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else lock_command="mv /etc/init.d/_${service_name} /etc/init.d/${service_name} ; /etc/init.d/${service_name} start" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then check_name=$( grep "${service_name}" "${restore_file}" | cut -f1 -d, ) if [ "$check_name" = "${service_name}" ]; then check_status=$( grep "${service_name}" "${restore_file}" | cut -f2 -d, ) restore_message="Service ${service_name} to ${check_status}" if [ "${check_status}" = "disabled" ]; then restore_command="/etc/init.d/${service_name} stop ; mv /etc/init.d/${service_name} /etc/init.d/_${service_name}" execute_restore "${restore_command}" "${restore_message}" else restore_command="mv /etc/init.d/_${service_name} /etc/init.d/${service_name} ; /etc/init.d/${service_name} start" execute_restore "${restore_command}" "${restore_message}" fi fi fi else inc_secure "Service \"${service_name}\" is \"${correct_status}\"" fi fi fi fi } ================================================ FILE: functions/sunos/check_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_service # # Service audit routine wrapper, sends to appropriate function based on service type # # service_name = Name of service # correct_status = What the status of the service should be, ie enable/disabled #. check_service () { if [ "${os_name}" = "SunOS" ]; then service_name="${1}" correct_status="${2}" print_function "check_service" service_test=$( echo "${service_name}" | grep "svc:" ) if [ -n "${service_test}" ]; then check_svcadm_service "${service_name}" "${correct_status}" else check_initd_service "${service_name}" "${correct_status}" check_inetd_service "${service_name}" "${correct_status}" fi fi } ================================================ FILE: functions/sunos/check_solaris_package.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # funct_check_pkg # # Check is a package is installed # # Install package if it's not installed and in the pkg dir under the base dir # Needs some more work #. funct_check_pkg () { if [ "${os_name}" = "SunOS" ]; then package_name="${1}" print_function "funct_check_pkg" package_check=$( pkginfo "${1}" ) log_file="${work_dir}/pkg.log" if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/pkg.log" if [ -f "${restore_file}" ]; then restore_check=$( grep "^${package_name}$" < "${restore_file}" | head -1 ) if [ "$restore_check" = "${package_name}" ]; then if [ "${os_version}" = "11" ]; then execute_restore "pkg uninstall ${package_name}" "Package \"${package_name}\"" "sudo" else execute_restore "pkgrm ${package_name}" "Package \"${package_name}\"" "sudo" fi fi fi else string="Package \"${package_name}\" is installed" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " package:" echo " name: ${package_name}" echo " state: present" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" fi package_test=$( echo "${package_check}" | grep "ERROR" ) if [ -z "${package_test}" ]; then inc_secure "Package \"${package_name}\" is already installed" else if [ "${audit_mode}" = 1 ]; then inc_insecure "Package \"${package_name}\" is not installed" pkg_dir="${base_dir}/pkg/${package_name}" if [ -d "$pkg_dir" ]; then install_message "Package \"${package_name}\"" if [ "${os_version}" = "11" ]; then pkgadd "${package_name}" else pkgadd -d "${base_dir}/pkg" "${package_name}" package_check=$( pkginfo "${1}" ) fi package_test=$( echo "${package_check}" | grep "ERROR" ) if [ -z "${package_check}" ]; then fix_message "${package_name}" >> "${log_file}" fi fi fi fi fi fi } ================================================ FILE: functions/sunos/check_sunos_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_sunos_service # # Service audit routine wrapper, sends to appropriate function based on service type # # service_name = Name of service # correct_status = What the status of the service should be, ie enable/disabled #. check_sunos_service () { if [ "${os_name}" = "SunOS" ]; then temp_name="${1}" temp_status="${2}" print_function "check_sunos_service" if [ "${temp_name}" = "disable" ] || [ "${temp_name}" = "enable" ]; then service_name=${temp_status} if [ "${temp_name}" = "disable" ]; then correct_status="disabled" else correct_status="enabled" fi else service_name="${temp_name}" correct_status="${temp_status}" fi service_test=$( echo "${service_name}" | grep "svc:" ) if [ -n "${service_test}" ]; then check_svcadm_service "${service_name}" "${correct_status}" else check_initd_service "${service_name}" "${correct_status}" check_inetd_service "${service_name}" "${correct_status}" fi fi } ================================================ FILE: functions/sunos/check_svcadm_service.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_svcadm_service # # Function to audit a svcadm service and enable or disable # # service_name = Name of service # correct_status = What the status of the service should be, ie enabled/disabled #. check_svcadm_service () { if [ "${os_name}" = "SunOS" ]; then service_name="${1}" correct_status="${2}" print_function "check_svcadm_service" file_header="svcadm" service_exists=$( svcs -a | grep "${service_name}" | awk '{print $3}' ) if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${file_header}.log" if [ -f "${restore_file}" ]; then restore_status=$( grep "^${service_name}" "${restore_file}" | cut -f2 -d, ) restore_test=$( echo "${restore_status}" | grep "[A-z]" ) if [ -n "${restore_test}" ]; then if [ "${restore_status}" != "${service_status}" ]; then restore_status=$( echo "${restore_status}" | sed "s/online/enable/g" | sed "s/offline/disable/g" ) restore_message="Service \"${service_name}\" to \"${restore_status}\"" restore_command="svcadm ${restore_status} ${service_name} ; svcadm refresh ${service_name}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi else if [ "${service_exists}" = "${service_name}" ]; then service_status=$( svcs -Ho state "${service_name}" ) log_file="${file_header}.log" string="Service ${service_name} is ${correct_status}" check_message "${string}" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " service:" echo " name: ${service_name}" echo " enabled: ${service_status}" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${service_status}" != "${correct_status}" ]; then inc_insecure "Service \"${service_name}\" is \"enabled\"" update_log "${log_file}" "${service_name},${service_status}" lock_message="Service \"${service_name}\" to \"${correct_status}\"" lock_command="inetadm -d ${service_name} ; svcadm refresh ${service_name}" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "Service \"${service_name}\" is already \"disabled\"" fi fi fi fi } ================================================ FILE: functions/sunos/create_ndd_script.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2129 # create_nddscript # # Creates an ndd boot script for Solaris # #. create_nddscript () { print_function "create_nddscript" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" != "11" ]; then check_message "Kernel ndd Parameters" check_file="/etc/init.d/ndd-netconfig" rcd_file="/etc/rc2.d/S99ndd-netconfig" if [ "${audit_mode}" = 0 ]; then if [ ! -f "${check_file}" ]; then echo "Creating: Init script \"${check_file}\"" printf "#!/sbin/sh" > "${check_file}" printf "case \"\$1\" in" >> "${check_file}" printf "start)" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip_forward_src_routed 0" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip_forwarding 0" >> "${check_file}" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then printf "\t/usr/sbin/ndd -set /dev/ip ip6_forward_src_routed 0" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/tcp tcp_rev_src_routes 0" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip6_forwarding 0" >> "${check_file}" fi printf "\t/usr/sbin/ndd -set /dev/ip ip_forward_directed_broadcasts 0" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/tcp tcp_conn_req_max_q0 4096" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/tcp tcp_conn_req_max_q 1024" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_timestamp 0" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_timestamp_broadcast 0" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_address_mask_broadcast 0" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_echo_multicast 0" >> "${check_file}" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then printf "\t/usr/sbin/ndd -set /dev/ip ip6_respond_to_echo_multicast 0" >> "${check_file}" fi printf "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_echo_broadcast 0" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/arp arp_cleanup_interval 60000" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip_ire_arp_interval 60000" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip_ignore_redirect 1" >> "${check_file}" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then printf "\t/usr/sbin/ndd -set /dev/ip ip6_ignore_redirect 1" >> "${check_file}" fi printf "\t/usr/sbin/ndd -set /dev/tcp tcp_extra_priv_ports_add 6112" >> "${check_file}" printf "\t/usr/sbin/ndd -set /dev/ip ip_strict_dst_multihoming 1" >> "${check_file}" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then printf "\t/usr/sbin/ndd -set /dev/ip ip6_strict_dst_multihoming 1" >> ${check_file} fi printf "\t/usr/sbin/ndd -set /dev/ip ip_send_redirects 0" >> "${check_file}" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then printf "\t/usr/sbin/ndd -set /dev/ip ip6_send_redirects 0" >> "${check_file}" fi printf "esac" >> ${check_file} printf "exit 0" >> ${check_file} chmod 750 ${check_file} if [ ! -f "${rcd_file}" ]; then ln -s "${check_file}" "${rcd_file}" fi fi else if [ "${audit_mode}" = 1 ]; then fix_message "" if [ ! -f "${check_file}" ]; then fix_message "Create an init script ${check_file} containing the following:" fix_message "#!/sbin/sh" fix_message "case \"\$1\" in" fix_message "start)" fix_message "\t/usr/sbin/ndd -set /dev/ip ip_forward_src_routed 0" fix_message "\t/usr/sbin/ndd -set /dev/ip ip_forwarding 0" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then fix_message "\t/usr/sbin/ndd -set /dev/ip ip6_forward_src_routed 0" fix_message "\t/usr/sbin/ndd -set /dev/tcp tcp_rev_src_routes 0" fix_message "\t/usr/sbin/ndd -set /dev/ip ip6_forwarding 0" fi fix_message "\t/usr/sbin/ndd -set /dev/ip ip_forward_directed_broadcasts 0" fix_message "\t/usr/sbin/ndd -set /dev/tcp tcp_conn_req_max_q0 4096" fix_message "\t/usr/sbin/ndd -set /dev/tcp tcp_conn_req_max_q 1024" fix_message "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_timestamp 0" fix_message "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_timestamp_broadcast 0" fix_message "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_address_mask_broadcast 0" fix_message "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_echo_multicast 0" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then fix_message "\t/usr/sbin/ndd -set /dev/ip ip6_respond_to_echo_multicast 0" fi fix_message "\t/usr/sbin/ndd -set /dev/ip ip_respond_to_echo_broadcast 0" fix_message "\t/usr/sbin/ndd -set /dev/arp arp_cleanup_interval 60000" fix_message "\t/usr/sbin/ndd -set /dev/ip ip_ire_arp_interval 60000" fix_message "\t/usr/sbin/ndd -set /dev/ip ip_ignore_redirect 1" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then fix_message "\t/usr/sbin/ndd -set /dev/ip ip6_ignore_redirect 1" fi fix_message "\t/usr/sbin/ndd -set /dev/tcp tcp_extra_priv_ports_add 6112" fix_message "\t/usr/sbin/ndd -set /dev/ip ip_strict_dst_multihoming 1" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then fix_message "\t/usr/sbin/ndd -set /dev/ip ip6_strict_dst_multihoming 1" fi fix_message "\t/usr/sbin/ndd -set /dev/ip ip_send_redirects 0" if [ "${os_version}" = "8" ] || [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ]; then fix_message "\t/usr/sbin/ndd -set /dev/ip ip6_send_redirects 0" fi fix_message "esac" fix_message "exit 0" fix_message "" fix_message "Then run the following command(s)" fix_message "chmod 750 ${check_file}" if [ ! -f "${rcd_file}" ]; then fix_message "ln -s ${check_file} ${rcd_file}" fi fi fi fi fi fi } ================================================ FILE: lunar.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2029 # shellcheck disable=SC2034 # shellcheck disable=SC2124 # shellcheck disable=SC2317 # shellcheck disable=SC2329 # shellcheck disable=SC3046 # Name: lunar (Lockdown UNix Auditing and Reporting) # Version: 15.9.1 # License: CC-BA (Creative Commons By Attribution) # http://creativecommons.org/licenses/by/4.0/legalcode # Group: System # Source: N/A # URL: http://lateralblast.com.au/ # Distribution: Solaris, Red Hat Linux, SuSE Linux, Debian Linux, # Ubuntu Linux, Mac OS X, AIX, FreeBSD, ESXi # Vendor: UNIX # Packager: Richard Spindler # Description: Audit script based on various benchmarks # Addition improvements added # Written in bourne shell so it can be run on different releases # No warranty is implied or given with this script # It is based on numerous security guidelines # As with any system changes, the script should be vetted and # changed to suit the environment in which it is being used # Unless your organization is specifically using the service, disable it. # The best defense against a service being exploited is to disable it. # Even if a service is set to off the script will audit the configuration # file so that if a service is re-enabled the configuration is secure # Where possible checks are made to make sure the package is installed # if the package is not installed the checks will not be run # To do: # # - nosuid,noexec for Linux # - Disable user mounted removable filesystems for Linux # - Disable USB devices for Linux # - Grub password # - Restrict NFS client requests to privileged ports Linux # Solaris Release Information # 1/06 U1 # 6/06 U2 # 11/06 U3 # 8/07 U4 # 5/08 U5 # 10/08 U6 # 5/09 U7 # 10/09 U8 # 9/10 U9 # 8/11 U10 # 1/13 U11 # audit_mode = 1 : Audit Mode # audit_mode = 0 : Lockdown Mode # audit_mode = 2 : Restore Mode # Azure check_azure=0 azure_auth_mode="login" azure_tenant_id="" azure_allow_no_subscriptions="no" azure_python_version="3.8" azure_java_version="11" azure_ftp_state="Disabled" azure_managed_identity="SystemAssigned" azure_sku_tier="Basic" azure_ase_version="ASEV3" #azure_ftp_state="FtpsOnly" # Defaults for AWS check_aws=0 aws_iam_master_role="iam-master" aws_iam_manager_role="iam-manager" aws_cloud_trail_name="aws-audit-log" sns_protocol="email" sns_endpoint="alerts@company.com" valid_tag_string="(ue1|uw1|uw2|ew1|ec1|an1|an2|as1|as2|se1)-(d|t|s|p)-([a-z0-9\-]+)$" strict_valid_names="y" check_volattach="y" check_voltype="y" check_snapage="y" aws_region="" aws_rds_min_retention="7" aws_ec2_min_retention="7" aws_ec2_max_retention="30" aws_days_to_key_deletion="7" # Defaults for MacOS keychain_sync="1" disable_airdrop="1" asset_cache="false" wifi_status="2" touchid_timeout="86400" # Defaults for SSH ssh_protocol="2" ssh_key_size="4096" ssh_allowusers="" ssh_allowgroups="" ssh_denyusers="" ssh_denygroups="" # Set up some counters secure_count=0 insecure_count=0 lockdown_count=0 restore_count=0 total_count=0 # Set up some global variables/defaults os_hostname=$( hostname -f ) app_dir=$( dirname "$0" ) args="$@" use_sudo=0 syslog_server="" syslog_logdir="" pkg_suffix="lunar" base_dir="/var/log/${pkg_suffix}" temp_dir="${base_dir}/tmp" date_suffix=$( date +%d_%m_%Y_%H_%M_%S ) temp_file="${temp_dir}/${pkg_suffix}.tmp" work_dir="${base_dir}/${date_suffix}" csv_dir="${base_dir}/csv" wheel_group="wheel" docker_group="docker" reboot_required=0 verbose_mode=0 command_mode=0 dryrun_mode=0 ansible_mode=0 ansible_counter=0 main_dir="${app_dir}/main" functions_dir="${app_dir}/functions" modules_dir="${app_dir}/modules" private_dir="${app_dir}/private" package_uninstall="no" country_suffix="au" language_suffix="en_US" osx_mdns_enable="yes" max_super_user_id="100" use_expr="no" use_finger="yes" test_os="none" test_tag="none" action="none" do_compose=0 do_multipass=0 do_shell=0 do_remote=0 my_id=$(id -u) tcpd_allow="sshd" do_audit=0 do_fs=0 audit_mode=1 audit_type="local" git_url="https://github.com/lateralblast/lunar.git" password_hashing="sha512" anacron_enable="no" ssh_sandbox="yes" do_debug=0 do_select=0 module_name="" no_cat=1 ubuntu_codename="" output_type="cli" output_file="" output_csv="Module,Check,Status,Fix" # Disable daemons nfsd_disable="yes" snmpd_disable="yes" dhcpcd_disable="yes" dhcprd_disable="yes" dhcpsd_disable="yes" sendmail_disable="yes" ipv6_disable="yes" routed_disable="yes" named_disable="yes" # verbose_message # # Print a message if verbose mode enabled #. verbose_message () { text="${1}" style="${2}" if [ "${verbose_mode}" = 1 ] && [ "${style}" = "fix" ]; then if [ "${text}" = "" ]; then echo "" else echo "[ Fix ] ${text}" output_csv="${output_csv},${text}" if [ ! "${output_file}" = "" ]; then case "${output_csv}" in *"check_"*) echo "${output_csv}" >> "${output_file}";; esac fi fi else case $style in audit*) echo "Auditing: ${text}" ;; backup) echo "Backup: ${text}" ;; check*) echo "Checking: ${text}" output_csv="${output_csv},${text}" ;; creat*) echo "Creating: ${text}" ;; delet*) echo "Deleting: ${text}" ;; exec*) if [ "${dryrun_mode}" = 0 ]; then echo "Executing: ${text}" else echo "Command: ${text}" fi ;; install*) echo "Installing: ${text}" ;; load*) echo "Loading: ${text}" ;; module) echo "Module: ${text}" if [ ! "${output_file}" = "" ]; then case "${output_csv}" in *"check_"*) echo "${output_csv}" >> "${output_file}";; esac fi output_csv="${text}" ;; notice) echo "Notice: ${text}" ;; remov*) echo "Removing: ${text}" ;; run*) echo "Running: ${text}" ;; sav*) echo "Saving: ${text}" ;; set*) echo "Setting: ${text}" ;; secur*) echo "Secure: ${text}" ;; updat*) echo "Updating: ${text}" ;; warn*) echo "Warning: ${text}" ;; na) echo "Notice: ${text} is not applicable on this system" ;; *) if [ "${verbose_mode}" = 1 ]; then echo "${text}" fi ;; esac fi } # warn_message # # Warning message #. warn_message () { verbose_message "${1}" "warn" } # info_message # # Information message #. info_message () { verbose_message "${1}" "info" } # lockdown_warning # # Check whether to proceed #. lockdown_warning () { if [ "${dryrun_mode}" = 0 ]; then if [ "${force}" != 1 ]; then warning_message "This will alter the system" printf "%s" "Do you want to continue? (yes/no): " while read -r reply do case "${reply}" in yes) return ;; *) exit ;; esac done fi fi } # Get our ID os_name=$( uname ) if [ "${os_name}" != "VMkernel" ]; then if [ "${os_name}" = "SunOS" ]; then id_check=$( id | cut -c5 ) else id_check=$( id -u ) fi arg_test=$(echo "$@" | grep -cE "\-h|-V|--help|--version|info" ) fi # Reset base dirs if not running as root if [ ! "${id_check}" = 0 ]; then base_dir="$HOME/.${pkg_suffix}" temp_dir="${base_dir}/tmp" temp_file="${temp_dir}/${pkg_suffix}.tmp" work_dir="${base_dir}/${date_suffix}" csv_dir="${base_dir}/csv" fi # Load main functions from main directory if [ -d "${main_dir}" ]; then if [ "${verbose_mode}" = "1" ]; then echo "" echo "Loading main functions" echo "" fi file_list=$( ls "${main_dir}"/*.sh ) for file_name in ${file_list}; do . "${file_name}" if [ "${verbose_mode}" = "1" ]; then verbose_message "\"${file_name}\"" "load" fi done fi # Install packages install_rsyslog="no" # This is the company name that will go into the security message # Change it as required company_name="Insert Company Name Here" # check_virtual_platform # # Check if we are running on a virtual platform #. check_virtual_platform () { virtual="Unknown" if [ -f "/.dockerenv" ]; then virtual="Docker" else dmi_check=$( command -v dmidecode | grep dmidecode | grep -cv no ) if [ "$dmi_check" = "1" ] && [ "${my_id}" = "0" ]; then virtual=$( dmidecode | grep Manufacturer |head -1 | awk '{print $2}' | sed "s/,//g" ) else virtual=$( uname -p ) if [ "${virtual}" = "unknown" ]; then virtual=$( uname -m ) fi fi fi echo "Platform: ${virtual}" } # execute_command # # Execute a command #. execute_command () { command="${1}" verbose_message "${command}" "execute" if [ "${dryrun_mode}" = 0 ]; then result=$( eval "${command}" ) echo "${result}" fi } # run_lockdown # # Run a lockdown command # Check that we are in lockdown mode # If not in lockdown mode output a verbose message #. run_lockdown () { command="${1}" message="${2}" privilege="${3}" if [ "${audit_mode}" = 0 ]; then total_count=$((total_count+1)) if [ "${message}" ]; then verbose_message "${message}" "set" fi verbose_message "${command}" "execute" if [ "${privilege}" = "" ]; then if [ "${dryrun_mode}" = 0 ]; then lockdown_count=$((lockdown_count+1)) sh -c "${command}" fi else if [ "$my_id" = "0" ]; then if [ "${dryrun_mode}" = 0 ]; then lockdown_count=$((lockdown_count+1)) sh -c "${command}" fi else if [ "${use_sudo}" = "1" ]; then if [ "${dryrun_mode}" = 0 ]; then lockdown_count=$((lockdown_count+1)) sudo sh -c "${command}" fi fi fi fi else verbose_message "${command}" "fix" fi } # execute_restore # # Run restore command # Check we are running in restore mode run a command #. execute_restore () { command="${1}" message="${2}" privilege="${3}" if [ "${audit_mode}" = 2 ]; then total_count=$((total_count+1)) if [ "${message}" ]; then verbose_message "${message}" "restore" fi verbose_message "${command}" "execute" if [ "${privilege}" = "" ]; then if [ "${dryrun_mode}" = 0 ]; then restore_count=$((restore_count+1)) sh -c "${command}" fi else if [ "$my_id" = "0" ]; then if [ "${dryrun_mode}" = 0 ]; then restore_count=$((restore_count+1)) sh -c "${command}" fi else if [ "${use_sudo}" = "1" ]; then if [ "${dryrun_mode}" = 0 ]; then restore_count=$((restore_count+1)) sudo sh -c "${command}" fi fi fi fi else verbose_message "${command}" "fix" fi } # # backup_state # # Backup state to a log file for later restoration #. backup_state () { if [ "${audit_mode}" = 0 ]; then backup_name="${1}" backup_value="${1}" backup_file="${work_dir}/${backup_name}.log" echo "$backup_value" > "${backup_file}" fi } # # restore_state # # Restore state from a log file #. restore_state () { if [ "${audit_mode}" = 2 ]; then restore_name="${1}" current_value="${2}" restore_command="${3}" restore_file="${restore_dir}/${restore_name}" if [ -f "${restore_file}" ]; then restore_value=$( cat "${restore_file}" ) if [ "${current_value}" != "${restore_value}" ]; then echo "Executing: ${command}" eval "${restore_command}" fi fi fi } # inc_secure # # Increment secure count #. inc_secure () { if [ "${audit_mode}" != 2 ]; then message="${1}" total_count=$((total_count+1)) secure_count=$((secure_count+1)) if [ "${secure_count}" = 1 ]; then echo "Secure: ${message} [${secure_count} Pass]" else echo "Secure: ${message} [${secure_count} Passes]" fi output_csv="${output_csv},PASS:${message}" fi } # inc_insecure # # Increment insecure count #. inc_insecure () { if [ "${audit_mode}" != 2 ]; then message="${1}" total_count=$((total_count+1)) insecure_count=$((insecure_count+1)) if [ "${insecure_count}" = 1 ]; then verbose_message "${message} [${insecure_count} Warning]" "warn" else verbose_message "${message} [${insecure_count} Warnings]" "warn" fi output_csv="${output_csv},FAIL:${message}" fi insecure_temp="${insecure_count}" } # Get the path the script starts from start_path=$( pwd ) # Get the version of the script from the script itself script_version=$( cd "${start_path}" || exit ; grep '^# Version' < "$0"| awk '{print $3}' ) # secure_baseline # # Establish a Secure Baseline # This uses the Solaris 10 svcadm baseline # Don't really need this so haven't coded anything for it yet #. secure_baseline () { : } # Handle command line arguments audit_mode=3 do_fs=0 audit_select=0 verbose_mode=0 force=0 do_select=0 do_aws=0 do_aws_rec=0 do_docker=0 print_funct=0 # If given no command line arguments print usage information if [ "$*" = "" ]; then print_help exit fi # Check environment for cloud providers case "$*" in *azure*) case "$*" in *--checkenv*) ;; *) check_azure_environment ;; esac ;; *aws*) case "$*" in *--checkenv*) ;; *) check_aws_environment ;; esac ;; *) if [ "${arg_test}" != "1" ]; then if [ "${id_check}" != "0" ]; then verbose_message "$0 may need root" "warn" fi fi ;; esac # check_switch_value # # Check if a value is a switch or empty #. check_switch_value () { param="${1}" value="${2}" if [ "${value}" = "" ]; then warn_message "No value provided for ${param}" exit fi case "${value}" in -*) warn_message "Value provided for ${param} appears to be a switch [${value}]" exit ;; esac } # Parse arguments while test $# -gt 0 do case $1 in -1|--list) # switch - List changes/backups check_switch_value "${1}" "${2}" list="${2}" if [ -z "${list}" ]; then print_changes print_backups shift exit else case ${list} in changes) print_changes ;; backups) print_backups ;; tests) print_tests "All" ;; esac shift 2 fi exit ;; -2|--tests) # switch - Print tests check_switch_value "${1}" "${2}" tests="${2}" if [ -z "${tests}" ]; then print_tests "All" else if [ "${tests}" = "--verbose" ]; then verbose_mode=1 print_tests "All" else print_tests "${tests}" shift 2 fi fi exit ;; -3|--printfunct) # switch - Print function print_funct=1 shift ;; -4|--dryrun) # switch - Run in dryrun mode dryrun_mode=1 shift ;; -5|--commands) # switch - Display command that would be run command_mode=1 shift ;; -6|--format) # switch - Outpt format/type check_switch_value "${1}" "${2}" output_type="${2}" shift 2 ;; -7|--file) # switch - Output file check_switch_value "${1}" "${2}" output_file="${2}" shift 2 ;; -8|--usesudo) # switch - Use sudo use_sudo=1 shift ;; -9|--checkenv) # switch - Run environment check check_switch_value "${1}" "${2}" check="${2}" do_check=1 shift 2 ;; -0|--force|--install) # switch - Force action or install requirements force=1 shift ;; -a|--audit) # switch - Run in audit mode (for Operating Systems - no changes made to system) audit_mode=1 do_fs=0 shift ;; -A|--fullaudit) # switch - Run in audit mode and include filesystems (for Operating Systems - no changes made to system) audit_mode=1 do_fs=1 shift ;; -b|--backups|--listbackups) # switch - List backups print_backups shift exit ;; -B|--basedir) # switch - Set base directory check_switch_value "${1}" "${2}" base_dir="${2}" shift 2 ;; -c|--codename|--distro) # switch - Distro/Code name (used with docker/multipass) check_switch_value "${1}" "${2}" test_distro="${2}" shift 2 ;; -C|--shell) # switch - Run docker-compose testing suite (drops to shell in order to do more testing) do_compose=1 do_shell=1 shift ;; -d|--dockeraudit) # switch - Run in audit mode (for Docker - no changes made to system) check_switch_value "${1}" "${2}" audit_mode=1 do_docker=1 module_name="${2}" shift 2 ;; -D|--dockertests) # switch - List all Docker functions available to selective mode print_tests "Docker" shift exit ;; -e|--host) # switch - Run in audit mode on external host (for Operating Systems - no changes made to system) check_switch_value "${1}" "${2}" do_remote=1 ext_host="${2}" shift 2 ;; -E|--hash|--passwordhash) # switch - Password hash check_switch_value "${1}" "${2}" password_hashing="${2}" shift 2 ;; -f|--action) # switch - Action (e.g delete - used with multipass) check_switch_value "${1}" "${2}" action="${2}" case $action in audit) audit_mode=1 do_fs=0 ;; fullaudit) audit_mode=1 do_fs=1 ;; lockdown) audit_mode=0 do_fs=0 ;; undo|restore) audit_mode=2 ;; osinfo|systeminfo) check_os_release exit ;; esac shift 2 ;; -F|--tempfile) # switch - Temporary file to use for operations check_switch_value "${1}" "${2}" temp_file="${2}" shift 2 ;; -g|--giturl) # switch - Git URL for code to copy to container check_switch_value "${1}" "${2}" git_url="${2}" shift 2 ;; -G|--wheelgroup) # switch - Set wheel group check_switch_value "${1}" "${2}" wheel_group="${2}" shift 2 ;; -h|--help) # switch - Display help print_help if [ "${verbose_mode}" = 1 ]; then print_usage fi shift exit 0 ;; -H|--usage) # switch - Display usage print_usage shift exit ;; -i|--anacron) # switch - Enable/Disable anacron check_switch_value "${1}" "${2}" anacron_enable="${2}" shift 2 ;; -I|--type) # switch - Audit type check_switch_value "${1}" "${2}" audit_type="${2}" shift 2 ;; -k|--kubeaudit) # switch - Run in audit mode (for Kubernetes - no changes made to system) check_switch_value "${1}" "${2}" audit_mode=1 do_kubernetes=1 module_name="${2}" shift 2 ;; -K|--function|--test) # switch - Do a specific function check_switch_value "${1}" "${2}" module_name="${2}" shift 2 ;; -l|--lockdown) # switch - Run in lockdown mode (for Operating Systems - changes made to system) audit_mode=0 do_fs=0 shift ;; -L|--fulllockdown|fulllock) # switch - Run in lockdown mode (for Operating Systems - changes made to system) audit_mode=0 do_fs=1 shift ;; -m|--machine|--vm) # switch - Set virtualisation type check_switch_value "${1}" "${2}" vm_type="${2}" case $vm_type in docker) do_compose=1 do_shell=0 ;; multipass) do_multipass=1 do_shell=0 ;; esac shift 2 ;; -M|--workdir) # switch - Set work directory check_switch_value "${1}" "${2}" work_dir="${2}" shift 2 ;; -n|--ansible) # switch - Output ansible ansible_mode=1 shift ;; -N|--nocat) # switch - Do output cat in score no_cat=1 shift ;; -o|--os|--osver) # switch - Set OS version check_switch_value "${1}" "${2}" test_os="${2}" shift 2 ;; -O|--osinfo|--systeminfo) # switch - Print OS/System information check_os_release shift exit ;; -p|--previous) # switch - Print previous audit information print_previous shift exit ;; -P|--sshsandbox|--sandbox) # switch - Enable/Disabe SSH sandbox check_switch_value "${1}" "${2}" ssh_sandbox="${2}" shift 2 ;; -q|--quiet|--nostrict) # switch - Run in quiet mode unset eu shift ;; -Q|--debug) # switch - Run in debug mode do_debug=1 set -ux shift ;; -r|--awsregion|--region) # switch - Set AWS region check_switch_value "${1}" "${2}" aws_region="${2}" shift 2 ;; -R|--moduleinfo|--testinfo) # switch - Print information about a module check_switch_value "${1}" "${2}" module="${2}" print_audit_info "${module}" shift 2 exit ;; -s|--select|--check) # switch - Run in selective mode (only run tests you want to) check_switch_value "${1}" "${2}" audit_mode=1 do_select=1 module_name="${2}" shift 2 ;; -S|--unixtests|--unix) # switch - List UNIX tests print_tests "UNIX" shift exit ;; -t|--tag|--name) # switch - Set docker tag check_switch_value "${1}" "${2}" test_tag="${2}" shift 2 ;; -T|--tempdir) # switch - Set temp directoru check_switch_value "${1}" "${2}" temp_dir="${2}" shift 2 ;; -u|--undo) # switch - Undo lockdown (for Operating Systems - changes made to system) check_switch_value "${1}" "${2}" audit_mode=2 restore_date="${2}" shift 2 ;; -U|--dofiles) # switch - Include filesystems do_fs=1 shift ;; -v|--verbose) # switch - Run in verbose mode verbose_mode=1 shift ;; -V|--version) # switch - Print version print_version shift exit ;; -w|--awsaudit) # switch - Run in audit mode (for AWS - no changes made to system) check_switch_value "${1}" "${2}" audit_mode=1 do_aws=1 module_name="${2}" shift 2 ;; -W|--awstests|--aws) # switch - List all AWS functions available to selective mode print_tests "AWS" shift exit ;; -x|--awsrec) # switch - Run in recommendations mode (for AWS - no changes made to system) check_switch_value "${1}" "${2}" audit_mode=1 do_aws_rec=1 module_name="${2}" shift 2 ;; -X|--strict) # switch - Run shellcheck against script unset eu shift exit ;; -z) # switch - Run specified audit function in lockdown mode check_switch_value "${1}" "${2}" audit_mode=0 do_fs=0 do_select=1 module_name="${2}" shift 2 ;; -Z|--changes|--listchanges) # switch - List changes print_changes shift exit ;; --tenant*) # switch - Azure tenant ID check_switch_value "${1}" "${2}" azure_tenant_id="${2}" shift 2 ;; --allow-no-subscriptions) # switch - Azure login allow no subscriptions azure_allow_no_subscriptions="yes" shift ;; *) print_help >&2 exit 1 ;; esac done # Run check if specified if [ "${do_check}" = 1 ]; then case "${check}" in *shell*) check_shellcheck ;; *azure*) check_azure_environment ;; *aws*) check_aws_environment ;; *docker*) check_docker ;; *multipass*) check_multipass ;; *env*) check_environment ;; *all*) check_all ;; *) verbose_message "Unknown check: ${check}" "error" exit ;; esac exit fi # Set Restore Directory if not set if [ "${audit_mode}" = 2 ]; then restore_dir="${base_dir}/${restore_date}" else if [ "${restore_dir}" = "" ]; then restore_dir="${work_dir}" fi fi # If running in dry run mode say so if [ "${dryrun_mode}" = 1 ]; then verbose_message "Running in dryrun mode" "notice" fi # If we are in lockdown mode do a check whether we are in force mode and whether to proceed if [ "${audit_mode}" = 0 ]; then lockdown_warning fi # Get function name module_name=$(echo "${module_name}" | tr '[:upper:]' '[:lower:]' | sed "s/ /_/g" ) # check arguments if [ "${do_audit}" = 1 ]; then if [ "${audit_type}" = "" ]; then audit_type="local" fi fi # Run script remotely if [ "${do_remote}" = 1 ]; then echo "Copying ${app_dir} to ${ext_host}:/tmp" scp -r "${app_dir}" "${ext_host}":/tmp echo "Executing lunar in audit mode (no changes will be made) on ${ext_host}" ssh "${ext_host}" "sudo sh -c \"${temp_dir}/lunar.sh -a\"" exit fi # Check environment check_environment # Setup output file and directory output_dir=$(dirname "${output_file}") if [ ! -d "${output_dir}" ]; then mkdir -p "${output_dir}" fi if [ "${output_type}" = "csv" ] && [ "${output_file}" = "" ]; then output_file="${csv_dir}/lunar_${os_hostname}_${date_suffix}.csv" fi if [ "${output_type}" = "csv" ]; then verbose_message "${output_file}" "create" echo "${output_csv}" > "${output_file}" fi # Run in docker or multipass if [ "${do_compose}" = 1 ] || [ "${do_multipass}" = 1 ]; then if [ "${do_multipass}" = 1 ]; then get_ubuntu_codename "${test_os}" test_os="${ubuntu_codename}" if [ "${test_tag}" = "none" ]; then if [ ! "${test_os}" = "none" ]; then test_tag="${pkg_suffix}-${test_os}" fi fi fi if [ ! "${test_os}" = "none" ] && [ ! "${test_tag}" = "none" ]; then if [ "${do_compose}" = 1 ]; then d_test=$(command -v docker-compose ) if [ -n "$d_test" ]; then if [ "$do_shell" = 0 ]; then cd "${app_dir}" || exit ; export OS_NAME="${test_os}" ; export OS_VERSION="${test_tag}" ; docker-compose run test-audit else cd "${app_dir}" || exit ; export OS_NAME="${test_os}" ; export OS_VERSION="${test_tag}" ; docker-compose run test-shell fi else verbose_message "Command docker-compose not found" "warn" exit fi else mpackage_test=$(command -v multipass | wc -l | sed "s/ //g" ) if [ "${mpackage_test}" = "1" ]; then vm_test=$(multipass list | awk '{print $1}' | grep -c "${test_tag}" ) if [ "${vm_test}" = "1" ]; then if [ "${action}" = "delete" ]; then verbose_message "Multipass VM \"${test_tag}\" with release \"${test_os}\"" "delete" multipass delete "${test_tag}" multipass purge else if [ "${do_shell}" = 1 ] || [ "${action}" = "shell" ]; then multipass shell "${test_tag}" else if [ "${action}" = "refresh" ]; then multipass exec "${test_tag}" -- bash -c "rm -rf lunar" multipass exec "${test_tag}" -- bash -c "git clone ${git_url}" else mp_command="sudo lunar/lunar.sh --action ${action}" if [ "${do_debug}" = "1" ]; then mp_command="${mp_command} --debug" fi if [ "${do_select}" = "1" ]; then mp_command="${mp_command} --select ${module_name}" fi multipass exec "${test_tag}" -- bash -c "${mp_command}" fi fi fi else if [ "${action}" = "delete" ]; then verbose_message "Multipass VM \"${test_tag}\" does not exist" exit else if [ "${action}" = "create" ]; then verbose_message "Multipass VM \"${test_tag}\" with release \"${test_os}\"" "create" multipass launch "${test_os}" --name "${test_tag}" multipass exec "${test_tag}" -- bash -c "git clone ${git_url}" exit fi fi fi else verbose_message "Command multipass not found" "warn" exit fi fi else echo "OS name or version not given" exit fi exit fi if [ "${audit_mode}" != 3 ]; then echo "" if [ "${audit_mode}" = 2 ]; then verbose_message "In Restore mode (changes will be made to system)" "run" verbose_message "Restore date ${restore_date}" "set" fi if [ "${audit_mode}" = 1 ]; then verbose_message "In audit mode (no changes will be made to system)" "run" fi if [ "${audit_mode}" = 0 ]; then verbose_message "In lockdown mode (changes will be made to system)" "run" fi if [ "${do_fs}" = 1 ]; then verbose_message "Filesystem checks will be done" "info" fi echo "" if [ "${do_select}" = 1 ]; then verbose_message "Selecting ${module_name}" "audit" funct_audit_select "${audit_mode}" "${module_name}" else case "${audit_type}" in Kubernetes) verbose_message "Kubernetes" "audit" funct_audit_kubernetes "${audit_mode}" exit ;; docker) verbose_message "Docker" "audit" funct_audit_docker "${audit_mode}" exit ;; awsrecommended) verbose_message "AWS - Recommended Tests" "audit" funct_audit_aws_rec "${audit_mode}" exit ;; aws) verbose_message "AWS" "audit" funct_audit_aws "${audit_mode}" exit ;; local|system|os) verbose_message "Operating System" "audit" funct_audit_system "${audit_mode}" exit ;; esac fi exit fi ================================================ FILE: main/check_environment.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC3046 # check_aws_environment # # Check AWS CLI etc is installed #. check_aws_environment () { print_function "check_aws_environment" aws_bin=$( command -v aws 2> /dev/null ) if [ -f "$aws_bin" ]; then aws_creds="$HOME/.aws/credentials" if [ -f "${aws_creds}" ]; then if [ "${os_name}" = "Darwin" ]; then base64_d="base64 -D" else base64_d="base64 -d" fi else echo "AWS credentials file does not exit" exit fi else echo "AWS CLI is not installed" exit fi if [ ! "${aws_region}" ]; then aws_region=$( aws configure get region ) fi } # check_azure_environment # # Check Azure CLI etc is installed #. check_azure_environment () { print_function "check_azure_environment" azure_bin=$( command -v az 2> /dev/null ) if [ -f "$azure_bin" ]; then for cli_ext in databricks bastion resource-graph application-insights nsp \ elastic-san site-recovery amlfs dataprotection databox redisenterprise \ datafactory; do info_message "Checking for Azure CLI extension \"${cli_ext}\"" command="az extension list --query \"[].name\" --output tsv | grep \"^${cli_ext}$\"" command_message "${command}" ext_test=$( eval "${command}" ) if [ -z "${ext_test}" ]; then if [ "${force}" = "1" ]; then info_message "Installing Azure CLI extension \"${cli_ext}\"" command="az extension add --name \"${cli_ext}\" 2> /dev/null" command_message "${command}" eval "${command}" else warn_message "Azure \"${cli_ext}\" extension is not installed" exit fi fi done else if [ "${force}" = "1" ]; then if [ "${os_name}" = "Darwin" ]; then brew_bin=$( command -v brew 2> /dev/null ) if [ -f "$brew_bin" ]; then command="brew install azure-cli" else command="pip install azure-cli" fi command_message "${command}" eval "${command}" else echo "Azure CLI is not installed" exit fi else echo "Azure CLI is not installed" exit fi fi command="az ad signed-in-user show --query displayName -o tsv" command_message "${command}" azure_display_name=$( eval "${command}" ) if [ -z "${azure_display_name}" ]; then if [ "${azure_allow_no_subscriptions}" = "yes" ]; then az login --allow-no-subscriptions else if [ -n "${azure_tenant_id}" ]; then az login --tenant "${azure_tenant_id}" else az login fi fi else verbose_message "Logged in as ${azure_display_name}" "notice" fi } # check_environment # # Do some environment checks # Create base and temporary directory #. check_environment () { print_function "check_environment" check_os_release if [ "${os_name}" = "Darwin" ]; then verbose_message "" "" info_message "Checking if node is managed" command="sudo pwpolicy -n -getglobalpolicy 2>&1 |cut -f1 -d:" command_message "${command}" managed_node=$( eval "${command}" ) if [ "${managed_node}" = "Error" ]; then notice_message "Node is not managed" else notice_message "Node is managed" fi verbose_message "" "" fi # Load functions from functions directory if [ -d "${functions_dir}" ]; then if [ "${verbose_mode}" = "1" ]; then echo "" echo "Loading Functions" echo "" fi file_list=$( find "${functions_dir}" -name "*.sh" ) for file_name in ${file_list}; do if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ] || [ "${os_vendor}" = "Debian" ] || [ "${os_vendor}" = "Ubuntu" ]; then . "${file_name}" else source "${file_name}" fi if [ "${verbose_mode}" = "1" ]; then verbose_message "\"${file_name}\"" "load" fi done fi # Load modules for modules directory if [ -d "${modules_dir}" ]; then if [ "${verbose_mode}" = "1" ]; then echo "" echo "Loading Modules" echo "" fi file_list=$( find "${modules_dir}" -name "*.sh" ) for file_name in ${file_list}; do if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ] || [ "${os_vendor}" = "Debian" ] || [ "${os_vendor}" = "Ubuntu" ]; then . "${file_name}" else if [ "${file_name}" = "modules/audit_ftp_users.sh" ]; then if [ "${os_name}" != "VMkernel" ]; then source "${file_name}" fi else source "${file_name}" fi fi if [ "${verbose_mode}" = "1" ]; then verbose_message "\"${file_name}\"" "load" fi done fi # Private modules for customers if [ -d "${private_dir}" ]; then echo "" echo "Loading Customised Modules" echo "" if [ "${verbose_mode}" = "1" ]; then echo "" fi file_list=$( find "${private_dir}" -name "*.sh" ) for file_name in ${file_list}; do if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ] || [ "${os_vendor}" = "Debian" ] || [ "${os_vendor}" = "Ubuntu" ]; then . "${file_name}" else source "${file_name}" fi done if [ "${verbose_mode}" = "1" ]; then echo "Loading: ${file_name}" fi fi if [ ! -d "${base_dir}" ]; then mkdir -p "${base_dir}" chmod 700 "${base_dir}" fi if [ ! -d "${temp_dir}" ]; then mkdir -p "${temp_dir}" fi if [ "${audit_mode}" = 0 ]; then if [ ! -d "${work_dir}" ]; then mkdir -p "${work_dir}" fi fi } ================================================ FILE: main/check_os_release.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # get_ubuntu_codename # # Get Ubuntu Codename #. get_ubuntu_codename () { print_function "get_ubuntu_codename" case "${1}" in "4.10") ubuntu_codename="warty" ;; "5.04") ubuntu_codename="hoary" ;; "5.10") ubuntu_codename="breezy" ;; "6.04") ubuntu_codename="dapper" ;; "6.10") ubuntu_codename="edgy" ;; "7.04") ubuntu_codename="feisty" ;; "7.10") ubuntu_codename="gutsy" ;; "8.04") ubuntu_codename="hardy" ;; "8.10") ubuntu_codename="intrepid" ;; "9.04") ubuntu_codename="jaunty" ;; "9.10") ubuntu_codename="karmic" ;; "10.04") ubuntu_codename="lucid" ;; "10.10") ubuntu_codename="maverick" ;; "11.04") ubuntu_codename="natty" ;; "11.10") ubuntu_codename="oneieric" ;; "12.04") ubuntu_codename="precise" ;; "12.10") ubuntu_codename="quantal" ;; "13.04") ubuntu_codename="raring" ;; "13.10") ubuntu_codename="saucy" ;; "14.04") ubuntu_codename="trusty" ;; "16.04") ubuntu_codename="xenial" ;; "18.04") ubuntu_codename="bionic" ;; "20.04") ubuntu_codename="focal" ;; "22.04") ubuntu_codename="jammy" ;; "24.04") ubuntu_codename="noble" ;; "24.10") ubuntu_codename="oracular" ;; "25.04") ubuntu_codename="plucky" ;; "25.10") ubuntu_codename="questing" ;; "26.04") ubuntu_codename="resolute" ;; *) ubuntu_codename="unknown" ;; esac } # check_os_release # # Get OS release information #. check_os_release () { print_function "check_os_release" echo "" echo "# Local System Information:" echo "" os_codename="" os_minorrev="" os_domain="unknown" os_platform="unknown" os_processor="unknown" os_vendor="unknown" os_release="unknown" os_version="unknown" os_update="unknown" os_codename="unknown" os_name=$( uname ) if [ "${os_name}" = "Darwin" ]; then os_release=$( sw_vers |grep ProductVersion |awk '{print $2}' ) os_version=$( echo "${os_release}" |cut -f1 -d. ) os_update=$( echo "${os_release}" |cut -f2 -d. ) os_vendor="Apple" if [ "${os_update}" = "" ]; then os_update=$( sw_vers |grep ^BuildVersion |awk '{print $2}' ) fi fi if [ "${os_name}" = "Linux" ]; then linux_dist=$( lsb_release -i -s | tr '[:upper:]' '[:lower:]' ) os_release=$( lsb_release -r 2> /dev/null |awk '{print $2}' ) if [ -f "/etc/redhat-release" ]; then os_version=$( awk '{print $3}' < /etc/redhat-release | cut -f1 -d. ) if [ "${os_version}" = "Enterprise" ]; then os_version=$( awk '{print $7}' < /etc/redhat-release | cut -f1 -d. ) if [ "${os_version}" = "Beta" ]; then os_version=$( awk '{print $6}' < /etc/redhat-release | cut -f1 -d. ) os_update=$( awk '{print $6}' < /etc/redhat-release | cut -f2 -d. ) else os_update=$( awk '{print $7}' < /etc/redhat-release | cut -f2 -d. ) fi else if [ "${os_version}" = "release" ]; then os_version=$( awk '{print $4}' < /etc/redhat-release | cut -f1 -d. ) os_update=$( awk '{print $4}' < /etc/redhat-release | cut -f2 -d. ) else os_update=$( awk '{print $3}' < /etc/redhat-release | cut -f2 -d. ) fi fi os_vendor=$( awk '{print $1}' < /etc/redhat-release ) linux_dist="redhat" else if [ -f "/etc/debian_version" ]; then if [ -f "/etc/lsb-release" ]; then os_version=$( grep "DISTRIB_RELEASE" /etc/lsb-release | cut -f2 -d= | cut -f1 -d. ) os_update=$( grep "DISTRIB_RELEASE" /etc/lsb-release | cut -f2 -d= | cut -f2 -d. ) os_vendor=$( grep "DISTRIB_ID" /etc/lsb-release | cut -f2 -d= ) os_codename=$( grep "DISTRIB_CODENAME" /etc/lsb-release | cut -f2 -d= ) os_minorrev=$( lsb_release -d |awk '{print $3}' |cut -f3 -d. ) else if [ -f "/etc/debian_version" ]; then os_version=$( cut -f1 -d. /etc/debian_version ) os_update=$( cut -f2 -d. /etc/debian_version ) os_vendor="Debian" else os_version=$( lsb_release -r | awk '{print $2}' | cut -f1 -d. ) os_update=$( lsb_release -r | awk '{print $2}' | cut -f2 -d. ) os_vendor=$( lsb_release -i | awk '{print $3}' ) fi fi linux_dist="debian" os_test=$( echo "${os_version}" | grep "[0-9]" ) if [ -n "$os_test" ]; then if [ ! -f "/usr/sbin/sysv-rc-conf" ] && [ "${os_version}" -lt 16 ]; then echo "Notice: The sysv-rc-conf package may be required by this script but is not present" fi fi if [ ! -f "/usr/bin/bc" ]; then use_expr="yes" fi if [ ! -f "/usr/bin/finger" ]; then use_finger="no" fi else if [ -f "/etc/SuSE-release" ]; then os_version=$( grep '^VERSION' /etc/SuSe-release | awk '{print $3}' | cut -f1 -d. ) os_update=$( grep '^VERSION' /etc/SuSe-release | awk '{print $3}' | cut -f2 -d. ) os_vendor="SuSE" linux_dist="suse" else if [ -f "/etc/arch-release" ]; then os_vendor="Arch" linux_dist="arch" else if [ -f "/etc/os-release" ]; then os_vendor="Amazon" os_version=$( grep 'CPE_NAME' /etc/os-release | cut -f2 -d: | cut -f1 -d. ) os_update=$( grep 'CPE_NAME' /etc/os-release | cut -f2 -d: | cut -f2 -d. ) fi fi fi fi fi fi if [ "${os_name}" = "SunOS" ]; then os_vendor="Oracle Solaris" os_version=$( uname -r |cut -f2 -d. ) if [ "${os_version}" = "11" ]; then os_update=$( grep Solaris /etc/release | awk '{print $3}' | cut -f2 -d. ) fi if [ "${os_version}" = "10" ]; then os_update=$( grep Solaris /etc/release | awk '{print $5}' | cut -f2 -d_ | sed 's/[A-z]//g' ) fi if [ "${os_version}" = "9" ]; then os_update=$( grep Solaris /etc/release | awk '{print $4}' | cut -f2 -d_ | sed 's/[A-z]//g' ) fi fi if [ "${os_name}" = "FreeBSD" ]; then os_version=$( uname -r | cut -f1 -d. ) os_update=$( uname -r | cut -f2 -d. ) os_vendor=${os_name} fi if [ "${os_name}" = "AIX" ]; then os_vendor="IBM" os_version=$( oslevel | cut -f1 -d. ) os_update=$( oslevel | cut -f2 -d. ) fi if [ "${os_name}" = "VMkernel" ]; then os_version=$( uname -r ) os_update=$( uname -v | awk '{print $4}' ) os_vendor="VMware" fi if [ "${os_name}" != "Linux" ] && [ "${os_name}" != "SunOS" ] && [ "${os_name}" != "Darwin" ] && [ "${os_name}" != "FreeBSD" ] && [ "${os_name}" != "AIX" ] && [ "${os_name}" != "VMkernel" ]; then echo "OS not supported" exit fi if [ "${os_name}" = "Linux" ]; then os_platform=$( grep model < /proc/cpuinfo |tail -1 |cut -f2 -d: |sed "s/^ //g" ) else if [ "${os_name}" = "Darwin" ]; then os_platform=$( system_profiler SPHardwareDataType |grep Chip |cut -f2 -d: |sed "s/^ //g" ) else os_platform=$( uname -p ) fi fi echo "Hostname: ${os_hostname}" os_domain=$( hostname -d ) if [ "${os_domain}" = "" ]; then os_domain=$( hostname -f | cut -f2- -d. ) fi if [ "${os_domain}" = "" ]; then if [ -f "/etc/domainname" ]; then os_domain=$( cat /etc/domainname ) fi fi if [ "${os_domain}" = "" ]; then os_domain="unknown" fi if [ "${os_domain}" = "(none)" ]; then os_domain="none" fi echo "Domain: ${os_domain}" os_machine=$( uname -m ) check_virtual_platform if [ "${os_platform}" = "" ]; then os_platform=$( uname -p ) fi echo "Processor: ${os_platform}" echo "Machine: ${os_machine}" echo "Vendor: ${os_vendor}" echo "Name: ${os_name}" if [ ! "${os_release}" = "" ]; then echo "Release: ${os_release}" fi echo "Version: ${os_version}" echo "Update: ${os_update}" if [ ! "${os_minorrev}" = "" ]; then echo "Minor Rev: ${os_minorrev}" fi echo "Codename: ${os_codename}" if [ "${os_name}" = "Darwin" ]; then if [ "${os_update}" -lt 10 ]; then long_update="0${os_update}" else long_update="${os_update}" fi long_os_version="${os_version}${long_update}" #echo "XRelease: ${long_os_version}" fi } ================================================ FILE: main/check_shellcheck.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # check_shellcheck # # Run shellcheck against script #. check_shellcheck () { print_function "check_shellcheck" bin_test=$( command -v shellcheck | grep -c shellcheck ) if [ ! "$bin_test" = "0" ]; then echo "Checking $0" shellcheck "$0" fi for dir_name in "${functions_dir}" "${modules_dir}"; do if [ -d "${dir_name}" ]; then file_list=$( find "${dir_name}" -name "*.sh" -type f -print ) for file_name in ${file_list}; do if [ "${verbose_mode}" = "1" ]; then verbose_message "\"${file_name}\"" "load" fi echo "Checking ${file_name}" shellcheck "${file_name}" done fi done } ================================================ FILE: main/get_info.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # get_service_name_from_port_no # # Get the service name from the port number # # Arguments: # ${1} - Port number # # Returns: # Service name get_service_name_from_port_no () { port_no="${1}" print_function "get_service_name_from_port_no" case "${port_no}" in 22) echo "SSH" ;; 53) echo "DNS" ;; 80) echo "HTTP" ;; 123) echo "NTP" ;; 161) echo "SNMP" ;; 389) echo "LDAP" ;; 443) echo "HTTPS" ;; 1900) echo "SSDP" ;; 3389) echo "RDP" ;; *) echo "Unknown" ;; esac } # cidr_to_mask # # Convert CIDR to netmask #. cidr_to_mask () { print_function "cidr_to_mask" set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0 if [ "${1}" -gt 1 ]; then shift "${1}" else shift fi echo "${1-0}"."${2-0}"."${3-0}"."${4-0}" } # mask_to_cidr # # Convert netmask to CIDR #. mask_to_cidr () { print_function "mask_to_cidr" x="${1##*255.}" set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x})*2 )) "${x%%.*}" x=${1%%"${3}"*} echo $(( $2 + (${#x}/4) )) } ================================================ FILE: main/print_info.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # print_version # # Print version information #. print_version () { print_function "print_version" echo "${script_version}" } # print_info # # Routing to parse script to print information like switch usage #. print_info () { info="${1}" print_function "print_info" echo "" echo "Usage: $0 -${info}|--${info}" echo "" if [ "${info}" = "switch" ]; then echo "${info}(es):" echo "-----------" else echo "${info}(s):" echo "----------" fi while read -r line; do test=$( echo "${line}" | grep "# ${info}" ) if [ "${test}" ]; then switch=$( echo "$line" |cut -f1 -d# ) desc=$( echo "$line" |cut -f2 -d# |sed "s/ ${info} - //g") echo "${switch}" echo " ${desc}" fi done < "$0" echo "" } # print_help # # If given a -h or no valid switch print usage information #. print_help () { print_function "print_help" print_info "switch" } # print_usage # # Print usage information # If given -H print some examples #. print_usage () { print_function "print_usage" echo "" echo "Examples:" echo "" echo "Run AWS CLI audit" echo "" echo "$0 -w" echo "" echo "Run Docker audit" echo "" echo "$0 -d" echo "" echo "Run in Audit Mode (for Operating Systems)" echo "" echo "$0 -a" echo "" echo "Run in Audit Mode and provide more information (for Operating Systems)" echo "" echo "$0 -a -v" echo "" echo "Display Previous Backups:" echo "" echo "$0 -b" echo "Previous Backups:" echo "21_12_2012_19_45_05 21_12_2012_20_35_54 21_12_2012_21_57_25" echo "" echo "Restore from Previous Backup:" echo "" echo "$0 -u 21_12_2012_19_45_05" echo "" echo "List tests:" echo "" echo "$0 -S" echo "" echo "Only run shell based tests:" echo "" echo "$0 -s audit_shell_services" echo "" } # print_backups # # Print backups #. print_backups () { print_function "print_backups" echo "" echo "Previous backups:" echo "" if [ -d "${base_dir}" ]; then find "${base_dir}" -maxdepth 1 -name "[0-9]*" -type d fi } # print_tests # # Print Tests #. print_tests () { test_string="${1}" print_function "print_tests" echo "" if [ "${test_string}" = "UNIX" ]; then grep_string="-v aws" else grep_string="${test_string}" fi echo "${test_string} Security Tests:" echo "" dir_list=$( find "${modules_dir}" -type f | grep -v "full_" | sed "s/\.sh//g" ) for dir_entry in ${dir_list} ; do case ${test_string} in AWS|aws) module_name=$( echo "${dir_entry}" | grep "aws" ) ;; *ocker*) module_name=$( echo "${dir_entry}" | grep "docker" ) ;; *ubernetes*|k8s) module_name=$( echo "${dir_entry}" | grep "kubernetes" ) ;; All|all) module_name="${dir_entry}" ;; *zure*) module_name=$( basename "${dir_entry}" | grep "azure_" ) ;; *) module_name=$( echo "${dir_entry}" | grep "${test_string}" ) ;; esac if [ -n "${module_name}" ]; then if [ "${verbose_mode}" -eq 1 ]; then print_audit_info "${module_name}" else echo "${module_name}" fi fi done echo "" } # print_function # # Print fuction name #. print_function() { funct_name="${1}" if [ "${verbose_mode}" -eq 1 ]; then echo "Function: ${funct_name}" fi } # print_changes # # Do a diff between previous file (saved) and existing file #. print_changes () { print_function "print_changes" if [ -f "${base_dir}" ]; then echo "" echo "Printing changes:" echo "" file_list=$( find "${base_dir}" -type f -print ) for saved_file in ${file_list}; do check_file=$( echo "${saved_file}" | cut -f 5- -d/ ) top_dir=$( echo "${saved_file}" | cut -f 1-4 -d/ ) echo "Directory: \"${top_dir}\"" log_test=$( echo "${check_file}" |grep "log$" ) if [ -n "${log_test}" ]; then echo "Original system parameters:" sed "s/,/ /g" < "${saved_file}" else echo "Changes to \"/${check_file}\":" diff "${saved_file}" "/${check_file}" fi done else echo "No changes made recently" fi } # print_previous # # Print previous changes #. print_previous () { print_function "print_previous" if [ -d "${base_dir}" ]; then echo "" echo "Printing previous settings:" echo "" if [ -d "${base_dir}" ]; then find "${base_dir}" -type f -print -exec cat -n {} \; fi fi } # handle_output # # Handle output #. handle_output () { text="${1}" echo "${1}" } # checking_message # # Checking message #. checking_message () { verbose_message "${1}" "check" } check_message () { verbose_message "${1}" "check" } # setting_message # # Setting message #. setting_message () { verbose_message "${1}" "set" } set_message () { verbose_message "${1}" "set" } # command_message # # Command message #. command_message () { if [ "${command_mode}" = 1 ]; then verbose_message "${1}" "exec" fi } # na_message # # Not Applicable message #. na_message () { if [ "${command_mode}" = 1 ]; then verbose_message "${1}" "na" fi } # notice_message # # Notice message #. notice_message () { if [ "${command_mode}" = 1 ]; then verbose_message "${1}" "notice" fi } # fix_message # # Fix message #. fix_message () { verbose_message "${1}" "fix" } # restore_message # # Restore message #. restore_message () { verbose_message "${1}" "restore" } # insecure_message # # Insecure message #. insecure_message () { verbose_message "${1}" "fix" } # backup_message # # Backup message #. backup_message () { verbose_message "${1}" "backup" } # install_message # # Install message #. install_message () { verbose_message "${1}" "install" } # remove_message # # Remove message #. remove_message () { verbose_message "${1}" "remove" } # save_message # # Save message #. save_message () { verbose_message "${1}" "save" } # print_audit_info # # This function searches the script for the information associated # with a function. # It finds the line starting with # function_name # then reads until it finds a #. #. print_audit_info () { module="${1}" print_function "print_audit_info" comment_text="0" dir_name=$( pwd ) check=$( echo "${module}" | grep "audit" ) if [ -z "${check}" ]; then module="audit_${module}" fi file_name="${dir_name}/modules/${module}.sh" if [ -f "${file_name}" ] ; then verbose_message "# Module: ${module}" while read -r line ; do if [ "${line}" = "# ${module}" ]; then comment_text=1 else if [ "${comment_text}" = 1 ]; then if [ "${line}" = "#." ]; then verbose_message "" comment_text=0 fi if [ "${comment_text}" = 1 ]; then verbose_message "${line}" fi fi fi done < "${file_name}" fi } # print_results # # Print Results #. print_results () { print_function "print_results" echo "" if [ "${reboot_required}" = 1 ]; then reboot_required="Required" else reboot_required="Not Required" fi percent=$( awk "BEGIN { pc=100*${secure_count}/${total_count}; i=int(pc); print (pc-i<0.5)?i:i+1 }" ) if [ "${no_cat}" = "1" ]; then echo "Tests: ${total_count}" case "${audit_mode}" in 2) echo "Restores: ${restore_count}" ;; 0) echo "Lockdowns: ${lockdown_count}" ;; *) echo "Passes: ${secure_count}" echo "Warnings: ${insecure_count}" echo "Score: ${percent}%" ;; esac echo "Reboot: ${reboot_required}" else echo " \ /\ Tests: ${total_count}" case "${audit_mode}" in 2) echo " ) ( ') Restores: ${restore_count}" echo " ( / ) " ;; 0) echo " ) ( ') Lockdowns: ${lockdown_count}" echo " ( / ) " ;; *) echo " ) ( ') Passes: ${secure_count}" echo " ( / ) Warnings: ${insecure_count}" echo " \(__)| Score: ${percent}%" ;; esac echo " Reboot: ${reboot_required}" fi if [ "${audit_mode}" = 0 ]; then echo "" echo "Backup: ${work_dir}" if [ ! "${module_name}" = "" ]; then echo "Restore: $0 -s ${module_name} -u ${date_suffix} -8" else echo "Restore: $0 -u ${date_suffix} -8" fi fi if [ "${output_type}" = "csv" ]; then echo "" echo "CSV File: ${output_file}" fi echo "" } ================================================ FILE: modules/accounting/audit_filesystem_partitions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_filesystem_partitions # # Check filesystems are on separate partitions # # Refer to Section(s) 1.1.1,5,7,8,9 Page(s) 14-21 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.1.1,5,7,8,9 Page(s) 15-22 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.1.1,5,7,8,9 Page(s) 18-26 CIS RHEL 6 Benchmark v1.0.0 # Refer to Section(s) 1.1.2,6-7 Page(s) 26-7,31-2 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 1.1.2.6-7 Page(s) 27-8,32-3 CIS Ubuntu LTS 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.1.2.[1-7].1 Page(s) 76-8,87-8,96-8, # 104-6,112-3, # 121-2,130-1 CIS Ubuntu LTS 24.04 Benchmark v1.0.0 # Refer to Section(s) 2.1,5,7,8,9 Page(s) 14-21 CIS SLES 11 Benchmark v1.2.0 # Refer to Section(s) 2.1,5,7,8,9 Page(s) 14-21 CIS SLES 11 Benchmark v1.2.0 # Refer to Section(s) 1.1.2,6-7,11-13 Page(s) 24-6,35-7 CIS Amazon Linux Benchmark v2.0.0 #. audit_filesystem_partitions () { print_function "audit_filesystem_partitions" string="Filesystem Partitions" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for filesystem in /tmp /var /var/log /var/log/audit /home /dev/shm /var/tmp; do mount_test=$( df | awk '{print $6}' | grep -c "^${filesystem}$" | sed "s/ //g" ) if [ ! "${mount_test}" = "0" ]; then inc_secure "Filesystem \"${filesystem}\" is a separate filesystem" else inc_insecure "Filesystem \"${filesystem}\" is not a separate filesystem" fi done else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_kernel_accounting.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kernel_accounting # # Check Kernel Accounting # # Refer to Section(s) 3.3 Page(s) 38-39 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 3.3 Page(s) 92 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 4.9 Page(s) 73-5 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 3.2,4-5 Page(s) 274-5,8-9,280-3 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_kernel_accounting () { print_function "audit_kernel_accounting" string="Kernel and Process Accounting" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Darwin" ]; then check_file="/etc/system" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then if [ -f "${check_file}" ]; then check_message "Kernel and Process Accounting" command="grep -v \"^\\*\" \"${check_file}\" | grep \"c2audit:audit_load\"" command_message "${command}" check_acc=$( eval "${command}" ) if [ -z "${check_acc}" ]; then check_file_value "is" "${check_file}" "c2audit" "colon" "audit_load" "star" if [ "${audit_mode}" = 0 ]; then log_file="${work_dir}/bsmconv.log" echo "y" >> "${log_file}" echo "y" | /etc/security/bsmconv fi fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/bsmconv.log" if [ -f "${restore_file}" ]; then echo "y" | /etc/security/bsmunconv fi fi check_file_value "is" "/etc/security/audit_control" "flags" "colon" "lo,ad,cc" "hash" check_file_value "is" "/etc/security/audit_control" "naflags" "colon" "lo,ad,ex" "hash" check_file_value "is" "/etc/security/audit_control" "minfree" "colon" "20" "hash" check_file_value "is" "/etc/security/audit_user" "root" "colon" "lo,ad:no" "hash" fi fi else check_file_perms "/etc/security/audit_control" "0750" "root" "${wheel_group}" check_file_perms "/var/audit" "0750" "root" "${wheel_group}" check_file_value "is" "/etc/security/audit_control" "flags" "colon" "lo,ad,fd,fm,-all" "hash" if [ "${os_version}" -ge 14 ]; then check_file_value "is" "/etc/security/audit_control" "expire-after" "colon" "60d" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_process_accounting.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_process_accounting # # Refer to Section(s) 10.1 Page(s) 137-8 CIS Solaris 10 Benchmark v1.1.0 #. audit_process_accounting () { print_function "audit_process_accounting" string="Process Accounting" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file="/etc/rc3.d/S99acct" init_file="/etc/init.d/acct" log_file="${work_dir}/acct.log" if [ ! -f "${check_file}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Process accounting not enabled" fi if [ "${audit_mode}" = 0 ]; then set_message "Process accounting to enabled" echo "disabled" > "${log_file}" ln -s "${init_file}" "${check_file}" notice_message "Starting Process accounting" eval "${init_file} start > /dev/null 2>&1" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Process accounting not enabled" fi if [ "${audit_mode}" = 2 ]; then log_file="${restore_dir}/acct.log" if [ -f "${log_file}" ]; then if [ -f "${check_file}" ]; then rm "${check_file}" fi restore_message "Process accounting to disabled" notice_message "Stoping Process accounting" eval "${init_file} stop > /dev/null 2>&1" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_sar_accounting.sh ================================================ #!/bin/sh - # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sar_accounting # # Check system accounting # # Refer to Section(s) 2.12.8 Page(s) 212-3 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 4.8 Page(s) 71-72 CIS Oracle Solaris 10 Benchmark v5.1.0 #. audit_sar_accounting () { print_function "audit_sar_accounting" string="SAR Accounting" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${os_name}" = "SunOS" ]; then check_append_file "/var/spool/cron/crontabs/adm" "0,20,40 * * * * /usr/lib/sa/sa1" "hash" check_append_file "/var/spool/cron/crontabs/adm" "45 23 * * * /usr/lib/sa/sa2 -s 0:00 -e 23:59 -i 1200 -A" "hash" fi if [ "${os_name}" = "AIX" ]; then package_name="bos.acct" check_lslpp ${package_name} if [ "${lslpp_check}" = "${package_name}" ]; then check_append_file "/var/spool/cron/crontabs/adm" "#=================================================================" "hash" check_append_file "/var/spool/cron/crontabs/adm" "# SYSTEM ACTIVITY REPORTS" "hash" check_append_file "/var/spool/cron/crontabs/adm" "# 8am-5pm activity reports every 20 mins during weekdays." "hash" check_append_file "/var/spool/cron/crontabs/adm" "# activity reports every an hour on Saturday and Sunday." "hash" check_append_file "/var/spool/cron/crontabs/adm" "# 6pm-7am activity reports every an hour during weekdays." "hash" check_append_file "/var/spool/cron/crontabs/adm" "# Daily summary prepared at 18:05." "hash" check_append_file "/var/spool/cron/crontabs/adm" "#=================================================================" "hash" check_append_file "/var/spool/cron/crontabs/adm" "0 8-17 * * 1-5 /usr/lib/sa/sa1 1200 3 &" "hash" check_append_file "/var/spool/cron/crontabs/adm" "0 * * * 0,6 /usr/lib/sa/sa1 &" "hash" check_append_file "/var/spool/cron/crontabs/adm" "0 18-7 * * 1-5 /usr/lib/sa/sa1 &" "hash" check_append_file "/var/spool/cron/crontabs/adm" "5 18 * * 1-5 /usr/lib/sa/sa2 -s 8:00 -e 18:01 -i 3600 -ubcwyaqvm &" "hash" else fix_message "Sar accounting requires \"${package_name}\" to be installed" fi fi check_dir="/var/adm/sa" if [ ! -d "${check_dir}" ]; then mkdir -p "${check_dir}" fi check_file_perms "${check_dir}" "0750" "adm" "adm" else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_system_accounting.sh ================================================ #!/bin/sh # -> Needs fixing # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2154 # audit_system_accounting # # Check system accounting # # Refer to Section(s) 4.2.1.1-18 Page(s) 77-96 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 5.3.1.1-21 Page(s) 113-136 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 5.2.1.1-18 Page(s) 86-9,100-120 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 4.1.1.1-3,4.2.1-18 Page(s) 164-191 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 8.1.1.1-18 Page(s) 86-106 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 5.2 Page(s) 18 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.11.4-5,17 Page(s) 194-5,202 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 4.8 Page(s) 71-2 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 4.1.1.1-3,4.2.1-18 Page(s) 148-75 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 4.1.1.1-3,4.1.2-18 Page(s) 159-86 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 4.1.2.1-3-4.1.3.29 Page(s) 440-527 CIS Ubuntu 22.04 Benchmark v1.0.0 # Refer to Section(s) 4.1.2.1-3-4.1.3.29 Page(s) 440-527 CIS Ubuntu 22.04 Benchmark v1.0.0 # Refer to Section(s) 6.2.2.1-4,6.2.3.1-21 Page(s) 807-97 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_system_accounting () { print_function "audit_system_accounting" string="System Accounting" check_message "${string}" max_log_file="8" max_log_file_action="keep_logs" disk_full_action="single" disk_error_action="single" space_left_action="single" admin_space_left_action="single" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_file_perms "/var/adm/sa" "0755" "adm" "adm" check_file_perms "/etc/security/audit" "0750" "root" "audit" check_file_perms "/audit" "0750" "root" "audit" fi if [ "${os_name}" = "FreeBSD" ]; then check_file_exists "/var/account/acct" "yes" check_file_value "is" "/etc/rc.conf" "accounting_enable" "eq" "YES" "hash" fi if [ "${os_name}" = "Linux" ]; then check_append_file "/etc/audit/audit.rules" "-w /var/log/sudo.log -p wa -k actions" "hash" check_linux_package "install" "sysstat" log_file="sysstat.log" if [ "${os_vendor}" = "Debian" ] || [ "${os_vendor}" = "Ubuntu" ]; then check_file_value "is" "/etc/default/sysstat" "ENABLED" "eq" "true" "hash" fi if [ "${package_name}" != "sysstat" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "System accounting not enabled" if [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "CentOS" ]; then fix_message "yum -y install ${package_check}" fi if [ "${os_vendor}" = "SuSE" ]; then fix_message "zypper install ${package_check}" fi if [ "${os_vendor}" = "Debian" ] || [ "${os_vendor}" = "Ubuntu" ]; then fix_message "apt-get install ${package_check}" fi fi if [ "${audit_mode}" = 0 ]; then set_message "System Accounting to enabled" log_file="${work_dir}/${log_file}" echo "Installed sysstat" >> "${log_file}" check_linux_package "install" "sysstat" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "System accounting enabled" fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" check_linux_package "restore" "sysstat" "${restore_file}" fi fi check_file="/etc/audit/rules.d/audit.rules" # Set failure mode to syslog notice check_append_file "${check_file}" "-f 1" "hash" # Things that could affect time check_append_file "${check_file}" "" "hash" # Things that modify time check_append_file "${check_file}" "-a always,exit -F arch=b32 -S adjtimex,settimeofday,clock_settime,stime -k time-change" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time-change" "hash" fi check_append_file "${check_file}" "-w /etc/localtime -p wa -k time-change" "hash" # Things that affect identity check_append_file "${check_file}" "-w /etc/group -p wa -k identity" "hash" check_append_file "${check_file}" "-w /etc/passwd -p wa -k identity" "hash" check_append_file "${check_file}" "-w /etc/gshadow -p wa -k identity" "hash" check_append_file "${check_file}" "-w /etc/shadow -p wa -k identity" "hash" check_append_file "${check_file}" "-w /etc/security/opasswd -p wa -k identity" "hash" # Things that could affect system locale check_append_file "${check_file}" "-a exit,always -F arch=b32 -S sethostname,setdomainname -k system-locale" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a exit,always -F arch=b64 -S sethostname,setdomainname -k system-locale" "hash" fi check_append_file "${check_file}" "-w /etc/issue -p wa -k system-locale" "hash" check_append_file "${check_file}" "-w /etc/issue.net -p wa -k system-locale" "hash" check_append_file "${check_file}" "-w /etc/hosts -p wa -k system-locale" "hash" check_append_file "${check_file}" "-w /etc/sysconfig/network -p wa -k system-locale" "hash" # Things that could affect MAC policy check_append_file "${check_file}" "-w /etc/selinux/ -p wa -k MAC-policy" "hash" # Things that could affect apparmor check_append_file "${check_file}" "-w /etc/apparmor/ -p wa -k MAC-policy" "hash" check_append_file "${check_file}" "-w /etc/apparmor.d/ -p wa -k MAC-policy" "hash" # Things that could affect logins check_append_file "${check_file}" "-w /var/log/faillog -p wa -k logins" "hash" check_append_file "${check_file}" "-w /var/log/lastlog -p wa -k logins" "hash" if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 16 ]; then check_append_file "${check_file}" "-w /var/run/faillock -p wa -k logins" "hash" fi # Process and session initiation (unsuccessful and successful) check_append_file "${check_file}" "-w /var/run/utmp -p wa -k session" "hash" check_append_file "${check_file}" "-w /var/log/btmp -p wa -k session" "hash" check_append_file "${check_file}" "-w /var/log/wtmp -p wa -k session" "hash" # Record chchon command usage check_append_file "${check_file}" "-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -k perm_chng" "hash" # Discretionary access control permission modification (unsuccessful and successful use of chown/chmod) check_append_file "${check_file}" "-a always,exit -S all -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng" "hash" check_append_file "${check_file}" "-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_chng" "hash" check_append_file "${check_file}" "-a always,exit -F arch=b32 -C euid!=uid -F auid!=unset -S execve -k user_emulation" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -C euid!=uid -F auid!=unset -S execve -k user_emulation" "hash" fi check_append_file "${check_file}" "-a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>=500 -F auid!=4294967295 -k perm_mod" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>=500 -F auid!=4294967295 -k perm_mod" "hash" fi check_append_file "${check_file}" "-a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>=500 - F auid!=4294967295 -k perm_mod" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>=500 - F auid!=4294967295 -k perm_mod" "hash" fi check_append_file "${check_file}" "-a always,exit -F arch=b32 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=500 -F auid!=4294967295 -k perm_mod" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=500 -F auid!=4294967295 -k perm_mod" "hash" fi #- Unauthorized access attempts to files (unsuccessful) check_append_file "${check_file}" "-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=500 -F auid!=4294967295 -k access" "hash" check_append_file "${check_file}" "-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=500 -F auid!=4294967295 -k access" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=500 -F auid!=4294967295 -k access" "hash" check_append_file "${check_file}" "-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=500 -F auid!=4294967295 -k access" "hash" fi #- Use of privileged commands (unsuccessful and successful) #check_append_file "${check_file}" "-a always,exit -F path=/bin/ping -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged" "hash" check_append_file "${check_file}" "-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -k priv_cmd" "hash" check_append_file "${check_file}" "-a always,exit -F arch=b32 -S mount -F auid>=500 -F auid!=4294967295 -k export" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -S mount -F auid>=500 -F auid!=4294967295 -k export" "hash" fi #- Files and programs deleted by the user (successful and unsuccessful) check_append_file "${check_file}" "-a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -k usermod" "hash" check_append_file "${check_file}" "-a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -F auid>=500 -F auid!=4294967295 -k delete" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=500 -F auid!=4294967295 -k delete" "hash" fi #- All system administration actions check_append_file "${check_file}" "-w /etc/sudoers -p wa -k scope" "hash" check_append_file "${check_file}" "-w /etc/sudoers.d -p wa -k scope" "hash" check_append_file "${check_file}" "-w /etc/sudoers -p wa -k actions" "hash" check_append_file "${check_file}" "-w /var/log/sudo.log -p wa -k sudo_log_file" "hash" #- Make sue kernel module loading and unloading is recorded check_append_file "${check_file}" "-w /sbin/insmod -p x -k modules" "hash" check_append_file "${check_file}" "-w /sbin/rmmod -p x -k modules" "hash" check_append_file "${check_file}" "-w /sbin/modprobe -p x -k modules" "hash" if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -S init_module,finit_module,delete_module,create_module,query_module -F auid>=1000 -F auid!=unset -k kernel_modules" "hash" fi check_append_file "${check_file}" "-a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset - k kernel_modules" "hash" check_append_file "${check_file}" "-a always,exit -S init_module -S delete_module -k modules" "hash" #- Tracks successful and unsuccessful mount commands if [ "${os_platform}" = "x86_64" ]; then check_append_file "${check_file}" "-a always,exit -F arch=b64 -S mount -F auid>=500 -F auid!=4294967295 -k mounts" "hash" fi check_append_file "${check_file}" "-a always,exit -F arch=b32 -S mount -F auid>=500 -F auid!=4294967295 -k mounts" "hash" #check_append_file "${check_file}" "" "hash" #- Manage and retain logs check_append_file "${check_file}" "space_left_action = ${space_left_action}" "hash" check_append_file "${check_file}" "action_mail_acct = email" "hash" check_append_file "${check_file}" "admin_space_left_action = ${admin_space_left_action}" "hash" check_append_file "${check_file}" "disk_full_action = ${disk_full_action}" "hash" check_append_file "${check_file}" "disk_error_action= ${disk_error_action}" "hash" check_append_file "${check_file}" "max_log_file = ${max_log_file}" "hash" check_append_file "${check_file}" "max_log_file_action = ${max_log_file_action}" "hash" #- Make file immutable - MUST BE LAST! check_append_file "${check_file}" "-e 2" "hash" for service_name in sysstat auditd; do check_linux_service "${service_name}" "on" done fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file="/var/spool/cron/crontabs/sys" check_append_file "${check_file}" "" "" if [ -f "${check_file}" ]; then command="grep -v \"^\\*\" \"${check_file}\" | grep \"sa2\"" command_message "${command}" sar_check=$( eval "${command}" ) fi if [ $( expr "${sar_check}" : "[A-z]" ) != 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "System Accounting is not enabled" fix_message "echo \"0,20,40 * * * * /usr/lib/sa/sa1\" >> ${check_file}" fix_message "echo \"45 23 * * * /usr/lib/sa/sa2 -s 0:00 -e 23:59 -i 1200 -A\" >> ${check_file}" fix_message "chown sys:sys /var/adm/sa/*" fix_message "chmod go-wx /var/adm/sa/*" fi if [ "${audit_mode}" = 0 ]; then set_message "System Accounting to enabled" if [ ! -f "${log_file}" ]; then echo "Saving: File ${check_file} to ${work_dir}${check_file}" find "${check_file}" | cpio -pdm "${work_dir}" 2> /dev/null fi command="echo \"0,20,40 * * * * /usr/lib/sa/sa1\" >> \"${check_file}\"" command_message "${command}" eval "${command}" command="echo \"45 23 * * * /usr/lib/sa/sa2 -s 0:00 -e 23:59 -i 1200 -A\" >> \"${check_file}\"" command_message "${command}" eval "${command}" command="chown sys:sys /var/adm/sa/*" command_message "${command}" eval "${command}" command="chmod go-wx /var/adm/sa/*" command_message "${command}" eval "${command}" if [ "${os_version}" = "10" ]; then command="pkgchk -f -n -p \"${check_file}\" 2> /dev/null" command_message "${command}" eval "${command}" else command="pkg fix $( pkg search \"${check_file}\" | grep pkg | awk '{print $4}' )" command_message "${command}" eval "${command}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "System Accounting is already enabled" fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_system_accounts.sh ================================================ #!/bin/sh # shellcheck disable=SC2034 # shellcheck disable=SC1090 # shellcheck disable=SC2154 # audit_system_accounts # # Check system accounts # # Refer to Section(s) 7.2 Page(s) 146-147 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 7.2 Page(s) 169 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 7.2 Page(s) 149-150 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.4.2 Page(s) 252 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 10.2 Page(s) 138-9 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 8.1 Page(s) 27 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 9.3 Page(s) 73-4 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 7.1 Page(s) 100-1 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 5.4.2 Page(s) 231 CIS Amazon Linux v2.0.0 # Refer to Section(s) 5.4.2 Page(s) 244 CIS Ubuntu 16.04 v2.0.0` # Refer to Section(s) 5.4.2.7 Page(s) 708-10 CIS Ubuntu 24.04 v1.0.0` #. audit_system_accounts () { print_function "audit_system_accounts" string="System Accounts that do not have a shell" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi password_file="/etc/passwd" shadow_file="/etc/shadow" if test -r "$shadow_file"; then if [ "${audit_mode}" != 2 ]; then command="awk -F: '(\$1!=\"root\" && \$1!=\"sync\" && \$1!=\"shutdown\" && \$1!=\"halt\" && \$3<500 && \$7!=\"/sbin/nologin\" && \$7!=\"/bin/false\" && \$7!=\"/usr/sbin/nologin\") {print \$1}' < \"${password_file}\"" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do command="grep \"${user_name}:\" \"${password_file}\" | cut -f7 -d:" command_message "${command}" shell_field=$( eval "${command}" ) if [ ! -f "${shell_field}" ] || [ "${shell_field}" = "" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "System account \"${user_name}\" has an invalid shell" if [ "${os_name}" = "FreeBSD" ]; then lock_command="pw moduser ${user_name} -s /sbin/nologin" fix_message "${lock_command}" else lock_command="usermod -s /sbin/nologin ${user_name}" fix_message "${lock_command}" fi fi if [ "${audit_mode}" = 0 ]; then lock_message="System account \"${user_name}\" to have shell /sbin/nologin" backup_file "${password_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi done else restore_file "${password_file}" "${restore_dir}" fi fi else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_system_auth.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth # # Check system auth settings # # Refer to Section(s) 6.3.1 Page(s) 160-1 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 6.3.5-6 Page(s) 163-5 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 5.3.1-2 Page(s) 238-41 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.3.1-2 Page(s) 220-1 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 5.3.1-4 Page(s) 232-6 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 5.3.1.1.1-3.1 Page(s) 598-656 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_system_auth () { print_function "audit_system_auth" string="Check system auth settings" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_file="/etc/security/pwquality.conf" check=0 if [ "${os_vendor}" = "Amazon" ] && [ "${os_version}" = "2016" ]; then check=1 fi if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 16 ]; then check_linux_package "install" "libpam-runtime" check_linux_package "install" "libpam-modules" check=1 fi if [ "${check}" -eq 1 ]; then check_file_value "is" "${check_file}" "minlen" "eq" "8" "hash" check_file_value "is" "${check_file}" "dcredit" "eq" "-1" "hash" check_file_value "is" "${check_file}" "ocredit" "eq" "-1" "hash" check_file_value "is" "${check_file}" "ucredit" "eq" "-1" "hash" check_file_value "is" "${check_file}" "lcredit" "eq" "-1" "hash" audit_system_auth_nullok audit_system_auth_unlock_time "auth" "unlock_time" "900" audit_system_auth_password_history "account" "remember" "5" audit_system_auth_password_hashing "password" "${password_hashing}" else if [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "CentOS" ] && [ "${os_version}" = "7" ]; then check_file_value "is" "${check_file}" "minlen" "eq" "8" "hash" check_file_value "is" "${check_file}" "dcredit" "eq" "-1" "hash" check_file_value "is" "${check_file}" "ocredit" "eq" "-1" "hash" check_file_value "is" "${check_file}" "ucredit" "eq" "-1" "hash" check_file_value "is" "${check_file}" "lcredit" "eq" "-1" "hash" audit_system_auth_nullok audit_system_auth_unlock_time "auth" "unlock_time" "900" audit_system_auth_password_history "account" "remember" "5" audit_system_auth_password_hashing "password" "${password_hashing}" else if [ "${audit_mode}" != 2 ]; then audit_system_auth_nullok audit_system_auth_password_history "account" "remember" "10" audit_system_auth_password_policy "password" "minlen" "8" audit_system_auth_password_policy "password" "dcredit" "-1" audit_system_auth_password_policy "password" "lcredit" "-1" audit_system_auth_password_policy "password" "ocredit" "-1" audit_system_auth_password_policy "password" "ucredit" "-1" audit_system_auth_unlock_time "auth" "unlock_time" "900" audit_system_auth_account_reset "account" "reset" audit_system_auth_password_strength "password" "16,12,8" audit_system_auth_no_magic_root "auth" "no_magic_root" fi fi fi if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 24 ]; then check_linux_package "install" "libpam-pwquality" check_file="/etc/security/pwquality.conf" check_file_value "is" "${check_file}" "maxsequence" "eq" "3" "hash" check_file_value "is" "${check_file}" "difok" "eq" "2" "hash" check_file_value "is" "${check_file}" "dictcheck" "eq" "0" "hash" check_file_value "is" "${check_file}" "lcredit" "eq" "0" "hash" check_file_value "not" "${check_file}" "enforcing" "eq" "0" "hash" check_append_file "${check_file}" "enforce_for_root" "hash" check_file="/etc/security/faillock.conf" check_append_file "${check_file}" "even_deny_root" "hash" check_file_value "is" "${check_file}" "root_unlock_time" "eq" "60" "hash" check_file_value "is" "${check_file}" "unlock_time" "eq" "900" "hash" check_file_value "is" "${check_file}" "deny" "eq" "5" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_system_auth_account_reset.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth_account_reset # # Check account reset settingd # # Refer to Section(s) 6.3.2 Page(s) 161-2 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.3.2 Page(s) 133-4 CIS SLES 11 Benchmark v1.0.0 #. audit_system_auth_account_reset () { auth_string="${1}" search_string="${2}" print_function "audit_system_auth_account_reset" string="Account Reset Settings" check_message "${string}" temp_file="${temp_dir}/audit_system_auth_account_reset" if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do if [ -f "${check_file}" ]; then check_value=$( grep "^${auth_string}" ${check_file} | grep "${search_string}$" | awk '{print $6}' ) if [ "${check_value}" != "${search_string}" ]; then if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 22 ]; then lock_command="awk '( \$1 == \"account\" && \$2 == \"required\" && \$3 == \"pam_failback.so\" ) { print \"auth\trequired\tpam_faillock.so onerr=fail no_magic_root reset\"; print $0; next };' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${audit_mode}" = "1" ]; then inc_insecure "Account reset entry not enabled in \"${check_file}\"" fix_message "rm ${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Account reset entry in \"${check_file}\"" fi else lock_command="awk '( \$1 == \"account\" && \$2 == \"required\" && \$3 == \"pam_tally2.so\" ) { print \"auth\trequired\tpam_tally2.so onerr=fail no_magic_root reset\"; print $0; next };' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${audit_mode}" = "1" ]; then inc_insecure "Account reset entry not enabled in \"${check_file}\"" fix_message "rm ${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Account reset entry in \"${check_file}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Account entry enabled in \"${check_file}\"" fi fi fi done else for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do restore_file "${check_file}" "${restore_dir}" done fi else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_system_auth_no_magic_root.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth_no_magic_root # # Make sure root account isn't locked as part of account locking #. audit_system_auth_no_magic_root () { auth_string="${1}" search_string="${2}" string="Make sure root account isn't locked as part of account locking" check_message "${string}" print_function "audit_system_auth_no_magic_root" temp_file="${temp_dir}/audit_system_auth_no_magic_root" if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do if [ -f "${check_file}" ]; then check_value=$( grep "^${auth_string}" "${check_file}" | grep "${search_string}$" | awk '{print $5}' ) if [ "${check_value}" != "${search_string}" ]; then if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 22 ]; then lock_command="cat ${temp_file} |awk '( \$1 == \"auth\" && \$2 == \"required\" && \$3 == \"pam_deny.so\" ) { print \"auth\trequired\tpam_faillock.so onerr=fail no_magic_root\"; print $0; next };' < ${check_file}> ${temp_file} ; cat ${temp} > ${check_file} ; rm ${temp_file}" else lock_command="cat ${temp_file} |awk '( \$1 == \"auth\" && \$2 == \"required\" && \$3 == \"pam_deny.so\" ) { print \"auth\trequired\tpam_tally2.so onerr=fail no_magic_root\"; print $0; next };' < ${check_file} > ${temp_file} ; cat ${temp} > ${check_file} ; rm ${temp_file}" fi if [ "${audit_mode}" = "1" ]; then inc_insecure "Auth entry not enabled in \"${check_file}\"" fix_message "rm ${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Setting: Auth entry in \"${check_file}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Auth entry enabled in \"${check_file}\"" fi fi fi done else for restore_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do restore_file "${restore_file}" "${restore_dir}" done fi else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_system_auth_nullok.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth_nullok # # Ensure null passwords are not accepted # # Refer to Section(s) 5.3.3.4.1 Page(s) 664-6 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_system_auth_nullok () { print_function "audit_system_auth_nullok" string="Ensure null passwords are not accepted" check_message "${string}" temp_file="${temp_dir}/audit_system_auth_nullok" if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do if [ -f "${check_file}" ]; then check_value=0 command="grep -v '^#' \"${check_file}\" | grep \"nullok\" | head -1 | wc -l | sed \"s/ //g\"" command_message "${command}" check_value=$( eval "${command}" ) lock_command="sed 's/ nullok//' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${check_value}" = 1 ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Found nullok \"entry\" in \"${check_file}\"" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Removing \"nullok\" entries from \"${check_file}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "No \"nullok\" entries in \"${check_file}\"" fi fi fi done else for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do restore_file "${check_file}" "${restore_dir}" done fi else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_system_auth_unlock_time.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth_unlock_time # # Check lockout time for failed password attempts enabled # # Refer to Section(s) 6.3.3 Page(s) 139-140 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.3.3 Page(s) 143-4 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.3.2 Page(s) 234 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_system_auth_unlock_time () { auth_string="${1}" search_string="${2}" search_value="${3}" print_function "audit_system_auth_unlock_time" string="Check lockout time for failed password attempts enabled" check_message "${string}" temp_file="${temp_dir}/audit_system_auth_unlock_time" if [ "${os_name}" = "Linux" ]; then os_check=0 if [ "${os_vendor}" = "Amazon" ]; then os_check=1 fi if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 16 ]; then if [ "${os_version}" -ge 22 ]; then os_check=0 else os_check=1 fi fi for check_file in /etc/pam.d/system-auth /etc/pam.d/common-auth; do if [ -f "${check_file}" ]; then if [ "${audit_mode}" != 2 ]; then check_value=$( grep "^${auth_string}" "${check_file}" | grep "${search_string}$" | awk -F '${search_string}=' '{print $2}' | awk '{print $1}' ) if [ "${check_value}" != "${search_string}" ]; then if [ "${os_check}" -eq 0 ]; then lock_command="sed 's/^auth.*pam_env.so$/&\nauth\t\trequired\t\t\tpam_faillock.so preauth audit silent deny=5 unlock_time=900\nauth\t\t[success=1 default=bad]\t\t\tpam_unix.so\nauth\t\t[default=die]\t\t\tpam_faillock.so authfail audit deny=5 unlock_time=900\nauth\t\tsufficient\t\t\tpam_faillock.so authsucc audit deny=5 ${search_string}=${search_value}\n/' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" else lock_command="awk '( \$1 == \"auth\" && \$2 == \"required\" && \$3 == \"pam_tally2.so\" ) { print \"auth\trequired\tpam_tally2.so onerr=fail audit silent deny=5 unlock_time=900\"; print \$0; next };' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" fi if [ "${audit_mode}" = 1 ]; then inc_insecure "Lockout time for failed password attempts not enabled in \"${check_file}\"" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Lockout time for failed password attempts in \"${check_file}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Lockout time for failed password attempts enabled in \"${check_file}\"" fi fi else for restore_file in /etc/pam.d/system-auth /etc/pam.d/common-auth; do restore_file "${restore_file}" "${restore_dir}" done fi fi done else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_system_auth_use_uid.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth_use_uid # # Check the use of su is restricted by sudo # # Refer to Section(s) 6.5 Page(s) 165-6 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 6.5 Page(s) 145-6 CIS RHEL 6 Benchmark v1.2.0 #. audit_system_auth_use_uid () { print_function "audit_system_auth_use_uid" string="Check the use of su is restricted by sudo" check_message "${string}" auth_string="auth" search_string="use_uid" check_file="/etc/pam.d/su" temp_file="${temp_dir}/audit_system_auth_use_uid" if [ -f "${check_file}" ]; then if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then lock_command="sed 's/^auth.*use_uid$/&\nauth\t\trequired\t\t\tpam_wheel.so use_uid\n/' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file}" command="grep \"^${auth_string}\" ${check_file} | grep \"${search_string}$\" | awk '{print \"\$8\"}'" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" != "${search_string}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "The use of su is not restricted by sudo in ${check_file}" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="The use of su to be restricted by sudo in ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "The use of su is restricted by sudo in \"${check_file}\"" fi fi else restore_file "${check_file}" "${restore_dir}" fi fi else na_message "${string}" fi } ================================================ FILE: modules/accounting/audit_system_integrity.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_integrity # # Check System Integrity Protection is enabled # # Refer to Section(s) 5.18 Page(s) 148-9 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 5.1.2,4 Page(s) 300-3,5-6 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_system_integrity () { print_function "audit_system_integrity" string="Check System Integrity Protection is enabled" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then command="/usr/bin/csrutil status | grep enabled" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_insecure "System Integrity Protection is not enabled" else inc_secure "System Integrity Protection is enabled" fi if [ "${os_version}" -ge 11 ]; then command="/usr/bin/csrutil authenticated-root status | grep enabled" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_insecure "Sealed System Volume is not enabled" else inc_secure "Sealed System Volume is enabled" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/aix/audit_i4ls.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_i4ls # # Check License Manager # # Refer to Section(s) 2.12.2 Page(s) 207 CIS AIX Benchmark v1.1.0 #. audit_i4ls () { print_function "audit_i4ls" string="License Manager" check_message "${string}" if [ "${os_name}" = "AIX" ]; then check_itab "i4ls" "off" else na_message "${string}" fi } ================================================ FILE: modules/aix/audit_writesrv.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_writesrv # # Refer to Section(s) 2.12.6 Page(s) 210-1 CIS AIX Benchmark v1.1.0 #. audit_writesrv () { print_function "audit_writesrv" string="Writesrv" check_message "${string}" if [ "${os_name}" = "AIX" ]; then check_itab "writesrv" "off" else na_message "${string}" fi } ================================================ FILE: modules/apache/audit_apache.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_apache # # Check Apache # # Refer to Section(s) 3.11,14 Page(s) 66-9 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.2.10 Page(s) 110 CIS Ubuntu Linux 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.17-8 Page(s) 273-9 CIS Ubuntu Linux 24.04 Benchmark v1.0.0 # Refer to Section(s) 3.11,14 Page(s) 79-81 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.11,14 Page(s) 69-71 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.10,13 Page(s) 110,113 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.10,13 Page(s) 59,61 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.4.14.7 Page(s) 56-7 CIS OS X 10.5 Benchmark v1.1.0 # Refer to Section(s) 2.10 Page(s) 21-2 CIS Solaris 11.1 v1.0.0 # Refer to Section(s) 2.2.11 Page(s) 21-2 CIS Solaris 10 v5.1.0 # Refer to Section(s) 2.2.10,13 Page(s) 102,105 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.10,13 Page(s) 110,113 CIS Ubuntu 16.04 Benchmark v2.0.0 # Refer to Section(s) 2-11 Page(s) 16-186 CIS Apache 2.2 Benchmark v3.6.0 # Refer to Section(s) 2-11 Page(s) 16-186 CIS Apache 2.4 Benchmark v1.5.0 #. audit_apache () { print_function "audit_apache" string="Apache and web based services" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/network/http:apache2" "disabled" fi if [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/http:apache2" "disabled" fi if [ "${os_version}" = "10" ]; then check_sunos_service "apache" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then for service_name in httpd apache apache2 tomcat5 squid prixovy nginx; do check_linux_service "${service_name}" "off" check_linux_package "uninstall" "${service_name}" done fi check_file_perms /var/log/httpd 0640 root apache for check_dir in /etc /etc/sfw /etc/apache /etc/apache2 /etc/apache2.2 /etc/apache/2.4 /usr/local/etc /usr/sfw/etc /opt/sfw/etc; do for check_file in "${check_dir}/httpd.conf" "${check_dir}/apache2.conf"; do if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "SSLHonorCipherOrder" "space" "On" "hash" check_file_value "is" "${check_file}" "SSLCipherSuite" "space" "EECDH:EDH:!NULL:!SSLv2:!RC4:!aNULL:!3DES:!IDEA" "hash" check_file_value "is" "${check_file}" "ServerTokens" "space" "Prod" "hash" check_file_value "is" "${check_file}" "ServerSignature" "space" "Off" "hash" check_file_value "is" "${check_file}" "SSLProtocol" "space" "TLSv1.2 TLSv1.3" "hash" check_file_value "is" "${check_file}" "SSLInsecureRenegotiation" "space" "Off" "hash" check_file_value "is" "${check_file}" "UserDir" "space" "Off" "hash" check_file_value "is" "${check_file}" "TraceEnable" "space" "Off" "hash" check_file_value "is" "${check_file}" "AllowOverride" "space" "None" "hash" check_file_value "is" "${check_file}" "Options" "space" "None" "hash" check_file_value "is" "${check_file}" "FileETag" "space" "None" "hash" check_file_value "is" "${check_file}" "User" "space" "apache" "hash" check_file_value "is" "${check_file}" "Group" "space" "apache" "hash" check_file_value "is" "${check_file}" "KeepAlive" "space" "On" "hash" check_file_value "is" "${check_file}" "MaxKeepAliveRequests" "space" "100" "hash" check_file_value "is" "${check_file}" "KeepAliveTimeout" "space" "15" "hash" check_file_value "is" "${check_file}" "TraceEnable" "space" "Off" "hash" check_file_value "is" "${check_file}" "RewriteEngine" "space" "On" "hash" check_file_value "is" "${check_file}" "RewriteOptions" "space" "Inherit" "hash" check_file_value "is" "${check_file}" "LimitRequestLine" "space" "512" "hash" check_file_value "is" "${check_file}" "LimitRequestFields" "space" "100" "hash" check_file_value "is" "${check_file}" "LimitRequestFieldsize" "space" "1024" "hash" check_file_value "is" "${check_file}" "LimitRequestBody" "space" "102400" "hash" check_file_value "is" "${check_file}" "Header" "space" "always append X-Frame-Options SAMEORIGIN" "hash" check_file_value "is" "${check_file}" "RewriteCond" "space" "%{THE_REQUEST} !HTTP/1\.1$" "hash" check_file_value "is" "${check_file}" "RewriteCond" "space" "%{HTTP_HOST} !^www\.example\.com [NC]" "hash" check_file_value "is" "${check_file}" "RewriteCond" "space" "%{REQUEST_URI} !^/error [NC]" "hash" check_file_value "is" "${check_file}" "RewriteRule" "space" ".* - [F]" "hash" check_file_value "is" "${check_file}" "RequestReadTimeout" "space" "header=20-40,MinRate=500 body=20,MinRate=500" "hash" check_file_value "is" "${check_file}" "LimitRequestBody" "space" "102400" "hash" check_file_value "not" "${check_file}" "LoadModule dav_module" "space" "modules/mod_dav.so" "hash" check_file_value "not" "${check_file}" "LoadModule dav_fs_module" "space" "modules/mod_dav_fs.so" "hash" check_file_value "not" "${check_file}" "LoadModule status_module" "space" "modules/mod_status.so" "hash" check_file_value "not" "${check_file}" "LoadModule autoindex_module" "space" "autoindex_module" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_module" "space" "modules/mod_proxy.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_balancer_module" "space" "modules/mod_proxy_balancer.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_ftp_module" "space" "modules/mod_proxy_ftp.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_http_module" "space" "modules/mod_proxy_http.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_connect_module" "space" "modules/mod_proxy_connect.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_ajp_module" "space" "modules/mod_proxy_ajp.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_fcgi_module" "space" "modules/mod_proxy_fcgi.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_scgi_module" "space" "modules/mod_proxy_scgi.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_express_module" "space" "modules/proxy_express_module.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_wstunnel_module" "space" "modules/proxy_wstunnel_module.so" "hash" check_file_value "not" "${check_file}" "LoadModule proxy_fdpass_module" "space" "modules/proxy_fdpass_module.so" "hash" check_file_value "not" "${check_file}" "LoadModule userdir_module" "space" "modules/mod_userdir.so" "hash" check_file_value "not" "${check_file}" "LoadModule info_module" "space" "modules/mod_info.so" "hash" check_file_value "not" "${check_file}" "LoadModule mod_auth_basic" "space" "modules/mod_auth_basic.so" "hash" check_file_value "not" "${check_file}" "LoadModule mod_auth_digest" "space" "modules/mod_auth_digest.so" "hash" check_file_value "is" "${check_file}" "LoadModule log_config_module" "space" "modules/mod_log_config.so" "hash" check_file_value "is" "${check_file}" "LoadModule rewrite_module" "space" "modules/mod_rewrite.so" "hash" check_file_value "is" "${check_file}" "LoadModule security2_module" "space" "modules/mod_security2.so" "hash" check_file_value "is" "${check_file}" "LoadModule reqtimeout_module" "space" "modules/mod_reqtimeout.so" "hash" fi done done else na_message "${string}" fi } ================================================ FILE: modules/audit/audit_auditd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_auditd # # Check auditd is installed - Required for various other tests like docker # # Refer to Section(s) 4.1 Page(s) 157-8 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 4.1.1.1-4 Page(s) 278-83 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 4.1.4.3,8 Page(s) 535-6,47-8 CIS Ubuntu 22.04 Benchmark v1.0.0 # Refer to Section(s) 6.2.4.1-10, Page(s) 799-806 CIS Ubuntu 24.04 Benchmark v1.0.0 # 6.2.1.1-4 899-922 # Refer to Section(s) 3.2 Page(s) 91 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 3.1 Page(s) 272-3 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_auditd () { print_function "audit_auditd" string="Audit Daemon" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then if [ "${os_name}" = "Linux" ]; then check_linux_package "install" "auditd" check_linux_package "install" "audispd-plugins" check_file="/etc/default/grub" app_name="Audit" package_name="audit" if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else if [ -f "${check_file}" ]; then package_disable_test=$( grep "${package_name}=0" "${check_file}" ) package_enabled_test=$( grep "${package_name}=1" "${check_file}" ) else package_disabled_test=0 package_enabled_test=0 fi if [ -n "${package_disabled_test}" ]; then temp_file="${temp_dir}/${package_name}" inc_insecure "Application \"${app_name}\" is disabled in \"${check_file}\"" backup_file "${check_file}" run_lockdown "cat ${check_file} |sed 's/${package_name}=0//g' > ${temp_file} ; cat ${temp_file} > ${check_file} ; update-grub" "Application \"${app_name}\" in \"${check_file}\" to disabled" else inc_secure "Application \"${app_name}\" is not disabled in \"${check_file}\"" fi if [ -n "${package_enabled_test}" ]; then inc_secure "Application \"${app_name}\" is enabled \"${check_file}\"" else temp_file="${temp_dir}/${package_name}" inc_insecure "Application \"${app_name}\" is not enabled in \"${check_file}\"" backup_file "${check_file}" line_check=$( grep "^GRUB_CMDLINE_LINUX" "${check_file}" ) if [ -n "${line_check}" ]; then existing_value=$( grep "^GRUB_CMDLINE_LINUX" "${check_file}" | cut -f2 -d= |sed "s/\"//g" ) new_value="GRUB_CMDLINE_LINUX=\"audit=1 ${existing_value}\"" run_lockdown "cat ${check_file} |sed 's/^GRUB_CMDLINE_LINUX/GRUB_CMDLINE_LINUX=\"${new_value}\"/g' > ${temp_file} ; cat ${temp_file} > ${check_file} ; update-grub" "Application \"${app_name}\" to enabled" else run_lockdown "echo 'GRUB_CMDLINE_LINUX=\"audit=1\"' >> ${check_file} ; update-grub" "Application \"${app_name}\" to enabled" fi fi fi package_name="audit_backlog_limit" package_value="8192" if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else if [ -f "${check_file}" ]; then package_disable_test=$( grep "${package_name}=0" "${check_file}" ) package_enabled_test=$( grep "${package_name}=${package_value}" "${check_file}" ) else package_disabled_test=0 package_enabled_test=0 fi if [ -n "${package_disabled_test}" ]; then temp_file="${temp_dir}/${package_name}" inc_insecure "${app_name} is disabled in ${check_file}" backup_file "${check_file}" lock_command="cat ${check_file} |sed 's/${package_name}=0//g' > ${temp_file} ; cat ${temp_file} > ${check_file} ; update-grub" lock_message="Application/Feature \"${app_name} \" in \"${check_file}\" to enabled" run_lockdown "${lock_command}" "${lock_message}" "sudo" existing_value=$( grep "^GRUB_CMDLINE_LINUX" "${check_file}" |cut -f2 -d= | sed "s/\"//g" ) new_value="GRUB_CMDLINE_LINUX=\"${package_name}=${package_value} ${existing_value}\"" lock_command="cat ${check_file} |sed 's/^GRUB_CMDLINE_LINUX/GRUB_CMDLINE_LINUX=\"${new_value}\"/g' > ${temp_file} ; cat ${temp_file} > ${check_file} ; update-grub" lock_message="Application/Feature \"${app_name}\" to enabled" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "${app_name} is not disabled in ${check_file}" fi if [ -n "${package_enabled_test}" ]; then inc_secure "${app_name} is enabled ${check_file}" else inc_insecure "${app_name} is not enabled in ${check_file}" temp_file="${temp_dir}/${package_name}" backup_file "${check_file}" line_check=$( grep "^GRUB_CMDLINE_LINUX" ${check_file} ) if [ -n "${line_check}" ]; then existing_value=$( grep "^GRUB_CMDLINE_LINUX" "${check_file}" | cut -f2 -d= |sed "s/\"//g" ) new_value="GRUB_CMDLINE_LINUX=\"${package_name}=${package_value} ${existing_value}\"" lock_command="cat ${check_file} |sed 's/^GRUB_CMDLINE_LINUX/GRUB_CMDLINE_LINUX=\"${new_value}\"/g' > ${temp_file} ; cat ${temp_file} > ${check_file} ; update-grub" lock_message="Application/Feature \"${app_name}\" to enabled" run_lockdown "${lock_command}" "${lock_message}" "sudo" else lock_command="echo 'GRUB_CMDLINE_LINUX=\"${package_name}=${package_value}\"' >> ${check_file} ; update-grub" lock_message="Application/Feature \"${app_name}\" to enabled" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi fi if [ "${os_name}" = "Darwin" ]; then check_launchctl_service "com.apple.auditd" "on" fi if [ "${os_name}" = "Linux" ]; then check_linux_service "auditd" "on" fi check_file="/etc/audit/auditd.conf" check_file_value "is" "${check_file}" "log_group" "eq" "adm" "hash" for check_file in /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/augenrules; do if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0750" "root" "root" fi done if [ -d "/etc/audit" ]; then command="find /etc/audit/ -type f \( -name '*.conf' -o -name '*.rules' \)" command_message "${command}" file_list=$( eval "${command}" ) for check_file in ${file_list}; do check_file_perms "${check_file}" "0640" "root" "root" done fi check_file="/var/log/audit/audit.log" if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0640" "root" "root" fi else na_message "${string}" fi } ================================================ FILE: modules/aws/compute/audit_aws_ec2.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_ec2 # # Check AWS EC2 # # Refer to https://www.cloudconformity.com/conformity-rules/EC2/default-securitygroups-in-use.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/ec2-instance-using-iam-roles.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/publicly-shared-ami.html # Refer to https://www.cloudconformity.com/conformity-rules/EBS/ebs-encrypted.html # Refer to https://www.cloudconformity.com/conformity-rules/EBS/ebs-encrypted-with-kms-customer-master-keys.html #. audit_aws_ec2 () { print_function "audit_aws_ec2" check_message "EC2" command="aws ec2 describe-instances --region \"${aws_region}\" --query 'Reservations[].Instances[].InstanceId' --filters \"Name=instance.group-name,Values=default\" --output text" command_message "${command}" instances=$( eval "${command}" ) if [ -z "${instances}" ]; then inc_secure "There are no instances using the default security group" else for instance in ${instances}; do inc_insecure "The instance \"${instance}\" is using the default security group" done fi command="aws ec2 describe-instances --region \"${aws_region}\" --query \"Reservations[].Instances[].InstanceId\" --output text" command_message "${command}" instances=$( eval "${command}" ) for instance in ${instances}; do command="aws ec2 describe-instances --region \"${aws_region}\" --instance-ids \"${instance}\" --query \"Reservations[*].Instances[*].IamInstanceProfile\" --output text" command_message "${command}" profile=$( eval "${command}" ) if [ -n "${profile}" ]; then inc_secure "Instances \"${instance}\" uses an IAM profile" else inc_insecure "Warning: Instance \"${instance}\" does not use an IAM profile" fi done command="aws ec2 describe-images --region \"${aws_region}\" --owners self --query \"Images[].ImageId\" --output text" command_message "${command}" images=$( eval "${command}" ) for image in ${images}; do command="aws ec2 describe-images --owners self --region \"${aws_region}\" --image-ids \"${image}\" --query \"Images[].Public\" | grep true" command_message "${command}" public=$( eval "${command}" ) if [ -z "${public}" ]; then inc_secure "Image \"${image}\" is not publicly shared" else inc_insecure "Image \"${image}\" is publicly shared" verbose_message "aws ec2 modify-image-attribute --region ${aws_region} --image-id ${image} --launch-permission '{\"Remove\":[{\"Group\":\"all\"}]}'" "fix" fi done command="aws ec2 describe-volumes --query \"Volumes[].VolumeId\" --output text" command_message "${command}" volumes=$( eval "${command}" ) for volume in ${volumes}; do command="aws ec2 describe-volumes --volume-id \"${volume}\" --query \"Volumes[].Encrypted\" | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "EBS Volume \"${volume}\" is encrypted" else inc_insecure "EBS Volume \"${volume}\" is not encrypted" fi # Check if KMS is being used command="aws ec2 describe-volumes --region \"${aws_region}\" --volume-ids \"${volume}\" --query 'Volumes[].KmsKeyId' --output text | cut -f2 -d/" command_message "${command}" key_id=$( eval "${command}" ) if [ -n "${key_id}" ]; then inc_secure "EBS Volume \"${volume}\" is encrypted with a KMS key" else inc_insecure "EBS Volume \"${volume}\" is encrypted not with a KMS key" fi done } ================================================ FILE: modules/aws/compute/audit_aws_elb.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_elb # # Check AWS ELB # # Refer to http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html # Refer to https://www.cloudconformity.com/conformity-rules/ELB/elb-access-log.html # Refer to https://www.cloudconformity.com/conformity-rules/ELB/elb-insecure-ssl-ciphers.html # Refer to https://www.cloudconformity.com/conformity-rules/ELB/elb-insecure-ssl-protocols.html # Refer to https://www.cloudconformity.com/conformity-rules/ELB/elb-listener-security.html # Refer to https://www.cloudconformity.com/conformity-rules/ELB/elb-security-group.html #. audit_aws_elb () { # Ensure ELBs have logging enabled print_function "audit_aws_elb" check_message "ELB" command="aws elb describe-load-balancers --region \"${aws_region}\" --query \"LoadBalancerDescriptions[].LoadBalancerName\" --output text" command_message "${command}" elbs=$( eval "${command}" ) for elb in ${elbs}; do command="aws elb describe-load-balancers --region \"${aws_region}\" --load-balancer-name \"${elb}\" --query \"LoadBalancerDescriptions[].AccessLog\" | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_insecure "ELB \"${elb}\" does not have access logging enabled" verbose_message "aws elb modify-load-balancer-attributes --region ${aws_region} --load-balancer-name ${elb} --load-balancer-attributes \"{\\\"AccessLog\\\":{\\\"Enabled\\\":true,\\\"EmitInterval\\\":60,\\\"S3BucketName\\\":\\\"elb-logging-bucket\\\"}}\"" fix else inc_secure "ELB \"${elb}\" has access logging enabled" fi # Ensure ELBs are not using HTTP command="aws elb describe-load-balancers --region \"${aws_region}\" --load-balancer-name \"${elb}\" --query \"LoadBalancerDescriptions[].ListenerDescriptions[].Listener[].Protcol\" --output text" command_message "${command}" protocol=$( eval "${command}" ) if [ "${protocol}" = "HTTP" ]; then inc_insecure "ELB \"${elb}\" is using HTTP" else inc_secure "ELB \"${elb}\" is not using HTTP" fi # Ensure ELB SGs do not have port 80 open to the world command="aws elb describe-load-balancers --region \"${aws_region}\" --load-balancer-name \"${elb}\" --query \"LoadBalancerDescriptions[].SecurityGroups\" --output text" command_message "${command}" sgs=$( eval "${command}" ) for sg in ${sgs}; do check_aws_open_port "${sg}" "80" "tcp" "HTTP" "ELB" "${elb}" done # Ensure no deprecated ciphers of protocols are being used command="aws elb describe-load-balancer-policies --region \"${aws_region}\" --load-balancer-name \"${elb}\" --output text" command_message "${command}" list=$( eval "${command}" ) for cipher in SSLv2 RC2-CBC-MD5 PSK-AES256-CBC-SHA PSK-3DES-EDE-CBC-SHA KRB5-DES-CBC3-SHA KRB5-DES-CBC3-MD5 \ PSK-AES128-CBC-SHA PSK-RC4-SHA KRB5-RC4-SHA KRB5-RC4-MD5 KRB5-DES-CBC-SHA KRB5-DES-CBC-MD5 \ EXP-EDH-RSA-DES-CBC-SHA EXP-EDH-DSS-DES-CBC-SHA EXP-ADH-DES-CBC-SHA EXP-DES-CBC-SHA \ SSLv3 EXP-RC2-CBC-MD5 EXP-KRB5-RC2-CBC-SHA EXP-KRB5-DES-CBC-SHA EXP-KRB5-RC2-CBC-MD5 \ EXP-KRB5-DES-CBC-MD5 EXP-ADH-RC4-MD5 EXP-RC4-MD5 EXP-KRB5-RC4-SHA EXP-KRB5-RC4-MD5; do check=$( echo "${list}" | grep ${cipher} | grep true ) if [ -n "${check}" ]; then inc_insecure "ELB \"${elb}\" is using deprecated cipher \"${cipher}\"" else inc_secure "ELB \"${elb}\" is not using deprecated cipher \"${cipher}\"" fi done done } ================================================ FILE: modules/aws/compute/audit_aws_es.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_es # # Check AWS Elasticsearch # # Refer to https://www.cloudconformity.com/conformity-rules/Elasticsearch/elasticsearch-domain-exposed.html # Refer to https://www.cloudconformity.com/conformity-rules/Elasticsearch/elasticsearch-accessible-only-from-whitelisted-ip-addresses.html #. audit_aws_es () { print_function "audit_aws_es" check_message "Elasticsearch" command="aws es list-domain-names --region \"${aws_region}\" --query \"DomainNames[].DomainName\" --output text" command_message "${command}" domains=$( eval "${command}" ) for domain in ${domains}; do command="aws es describe-elasticsearch-domain --domain-name \"${domain}\" --query 'DomainStatus.AccessPolicies' --output text | grep Principle | grep \"{\\\"AWS\\\":\\\"\\*\\\"}\"" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_secure "Elasticsearch domain \"${domain}\" is not publicly accessible" else inc_insecure "Elasticsearch domain \"${domain}\" is publicly accessible" fi command="aws es describe-elasticsearch-domain --domain-name \"${domain}\" --query 'DomainStatus.AccessPolicies' --output text | grep \"aws:SourceIp\" | grep \"[0-9]\.\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Elasticsearch doamin \"${domain}\" has an IP based access policy" else inc_insecure "Elasticsearch domain \"${domain}\" does not have and IP based access policy" fi done } ================================================ FILE: modules/aws/compute/audit_aws_rec_ec2.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_ec2 # # Check EC2 Recommendations # # Refer to https://www.cloudconformity.com/conformity-rules/EC2/ami-naming-conventions.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/approved-golden-amis.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/ec2-instance-naming-conventions.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/ec2-instance-termination-protection.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/security-group-naming-conventions.html # Refer to https://www.cloudconformity.com/conformity-rules/EBS/ebs-naming-conventions.html # Refer to https://www.cloudconformity.com/conformity-rules/EBS/general-purpose-ssd-volume.html # Refer to https://www.cloudconformity.com/conformity-rules/EBS/ebs-volumes-too-old-snapshots.html # Refer to https://www.cloudconformity.com/conformity-rules/EBS/unused-ebs-volumes.html # Refer to https://www.cloudconformity.com/conformity-rules/EBS/ebs-volumes-recent-snapshots.html #. audit_aws_rec_ec2 () { print_function "audit_aws_rec_ec2" check_message "EC2 Recommendations" command="aws ec2 describe-volumes --region \"${aws_region}\" --query 'Volumes[].VolumeId' --output text" command_message "${command}" volumes=$( eval "${command}" ) for volume in ${volumes}; do if [ "${check_volattach}" = "y" ]; then # Check for EC2 volumes that are unattached command="aws ec2 describe-volumes --region \"${aws_region}\" --volume-id \"${volume}\" --query 'Volumes[].State' --output text" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" = "available" ]; then inc_secure "EC2 volume \"${volume}\" is attached to an instance" else inc_insecure "EC2 volume \"${volume}\" is not attached to an instance" fi fi if [ "${check_volattach}" = "y" ]; then # Check that EC2 volumes are using cost effective storage command="aws ec2 describe-volumes --region \"${aws_region}\" --volume-id \"${volume}\" --query 'Volumes[].VolumeType' | grep \"gp2\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "EC2 volume \"${volume}\" is using General Purpose SSD" else inc_insecure "EC2 volume \"${volume}\" is not using General Purpose SSD" fi fi done # Check date of snapshots if [ "${check_snapage}" = "y" ]; then command="aws iam get-user --query \"User.Arn\" --output text | cut -f5 -d:" command_message "${command}" arn=$( eval "${command}" ) command="aws ec2 describe-snapshots --region \"${aws_region}\" --owner-ids \"${arn}\" --filters ansible_value=status,Values=completed --query \"Snapshots[].SnapshotId\" --output text" command_message "${command}" snapshots=$( eval "${command}" ) counter=0 for snapshot in ${snapshot}s; do command="aws ec2 describe-snapshots --region \"${aws_region}\" --snapshot-id \"${snapshot}\" --query \"Snapshots[].StartTime\" --output text --output text | cut -f1 -d." command_message "${command}" snap_date=$( eval "${command}" ) if [ "${os_name}" = "Linux" ]; then command="date -d \"${snap_date}\" \"+%s\"" command_message "${command}" snap_secs=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%SS\" \"${snap_date}\" \"+%s\"" command_message "${command}" snap_secs=$( eval "${command}" ) fi command="date \"+%s\"" command_message "${command}" curr_secs=$( eval "${command}" ) command="echo \"(${curr_secs} - ${snap_secs})/84600\" | bc" command_message "${command}" diff_days=$( eval "${command}" ) if [ "${diff_days}" -gt "${aws_ec2_max_retention}" ]; then inc_insecure "EC2 snapshot \"${snapshot}\" is more than \"${aws_ec2_max_retention}\" days old" else inc_secure "EC2 snapshot \"${snapshot}\" is less than \"${aws_ec2_max_retention}\" days old" fi if [ "${diff_days}" -gt "${aws_ec2_min_retention}" ]; then counter=$((counter+1)) fi done if [ "${counter}" -gt 0 ]; then inc_secure "There are EC2 snapshots more than \"${aws_ec2_min_retention}\" days old" else inc_insecure "There are no EC2 snapshots more than \"${aws_ec2_min_retention}\" days old" fi fi # Check Security Groups have Name tags command="aws ec2 describe-security-groups --region \"${aws_region}\" --query 'SecurityGroups[].GroupId' --output text" command_message "${command}" sgs=$( eval "${command}" ) for sg in ${sgs}; do if [ ! "${sg}" = "default" ]; then command="aws ec2 describe-security-groups --region \"${aws_region}\" --group-id \"${sg}\" --query \"SecurityGroups[].Tags[?Key==\\\`Name\\\`].Value\" 2> /dev/null --output text" command_message "${command}" ansible_value=$( eval "${command}" ) if [ -z "${ansible_value}" ]; then inc_insecure "AWS Security Group \"${sg}\" does not have a Name tag" verbose_message "aws ec2 create-tags --region \"${aws_region}\" --resources \"${image}\" --tags Key=Name,Value=" "fix" else if [ "${strict_valid_names}" = "y" ]; then command="echo \"${ansible_value}\" |grep \"^sg-${valid_tag_string}\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "AWS Security Group \"${sg}\" has a valid Name tag" else inc_insecure "AWS Security Group \"${sg}\" does not have a valid Name tag" fi fi fi fi done # Check Volumes have Name tags command="aws ec2 describe-volumes --region \"${aws_region}\" --query \"Volumes[].VolumeId\" --output text" command_message "${command}" volumes=$( eval "${command}" ) for volume in ${volumes}; do command="aws ec2 describe-volumes --region \"${aws_region}\" --volume-id \"${volume}\" --query \"Volumes[].Tags[?Key==\\\`Name\\\`].Value\" --output text" command_message "${command}" ansible_value=$( eval "${command}" ) if [ -z "${ansible_value}" ]; then inc_insecure "AWS EC2 volume \"${volume}\" does not have a Name tag" verbose_message "aws ec2 create-tags --region \"${aws_region}\" --resources \"${volume}\" --tags Key=Name,Value=" "fix" else if [ "${strict_valid_names}" = "y" ]; then command="echo \"${ansible_value}\" |grep \"^ami-${valid_tag_string}\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "AWS EC2 volume \"${volume}\" has a valid Name tag" else inc_insecure "AWS EC2 volume \"${volume}\" does not have a valid Name tag" fi fi fi done # Check AMIs have Name tags command="aws ec2 describe-images --region \"${aws_region}\" --owners self --query \"Images[].ImageId\" --output text" command_message "${command}" images=$( eval "${command}" ) for image in ${images}; do command="aws ec2 describe-images --region \"${aws_region}\" --owners self --image-id \"${image}\" --query \"Images[].Tags[?Key==\\\`Name\\\`].Value\" --output text" command_message "${command}" ansible_value=$( eval "${command}" ) if [ -z "${ansible_value}" ]; then inc_insecure "AWS AMI \"${image}\" does not have a Name tag" verbose_message "aws ec2 create-tags --region \"${aws_region}\" --resources \"${image}\" --tags Key=Name,Value=" "fix" else if [ "${strict_valid_names}" = "y" ]; then command="echo \"${ansible_value}\" |grep \"^ami-${valid_tag_string}\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "AWS AMI \"${image}\" has a valid Name tag" else inc_insecure "AWS AMI \"${image}\" does not have a valid Name tag" fi fi fi done # Check Instances have Name tags command="aws ec2 describe-instances --region \"${aws_region}\" --query \"Reservations[].Instances[].InstanceId\" --output text" command_message "${command}" instances=$( eval "${command}" ) for instance in ${instances}; do for tag in Name Role Environment Owner; do command="aws ec2 describe-instances --region \"${aws_region}\" --instance-id \"${instance}\" --query \"Reservations[].Instances[].Tags[?Key==\\\`${tag}\\\`].Value\" --output text" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_insecure "AWS Instance \"${instance}\" does not have a \"${tag}\" tag" verbose_message "aws ec2 create-tags --region \"${aws_region}\" --resources \"${instance}\" --tags Key=${tag},Value=" "fix" else if [ "${strict_valid_names}" = "y" ]; then command="echo \"${ansible_value}\" |grep \"^ec2-${valid_tag_string}\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "AWS Instance \"${instance}\" has a valid \"${tag}\" tag" else inc_insecure "AWS Instance \"${instance}\" does not have a valid \"${tag}\" tag" fi fi fi done command="aws ec2 describe-instance-attribute --region \"${aws_region}\" --instance-id \"${instance}\" --attribute disableApiTermination --query \"DisableApiTermination\" | grep -i true" command_message "${command}" term_check=$( eval "${command}" ) command="aws autoscaling describe-auto-scaling-instances --region \"${aws_region}\" --query 'AutoScalingInstances[].InstanceId' | grep \"${instance}\"" command_message "${command}" asg_check=$( eval "${command}" ) if [ -n "${term_check}" ] && [ -z "${asg_check}" ]; then inc_secure "Termination Protection is enabled for instance \"${instance}\"" else inc_insecure "Termination Protection is not enabled for instance \"${instance}\"" fi done # Check Instances are from self produced images command="aws ec2 describe-instances --region \"${aws_region}\" --query 'Reservations[].Instances[].ImageId' --output text" command_message "${command}" images=$( eval "${command}" ) for image in ${images}; do command="aws ec2 describe-images --region \"${aws_region}\" --image-ids \"${image}\" --query 'Images[].ImageOwnerAlias' --output text" command_message "${command}" owner=$( eval "${command}" ) if [ "${owner}" = "self" ] || [ -z "${owner}" ]; then inc_secure "AWS AMI \"${image}\" is a self produced image" else inc_insecure "AWS AMI \"${image}\" is not have a valid Name tag" fi done # Check number of Elastic IPs that are being used command="aws ec2 describe-account-attributes --region \"${aws_region}\" --attribute-names max-elastic-ips --query \"AccountAttributes[].AttributeValues[].AttributeValue\" --output text" command_message "${command}" max_ips=$( eval "${command}" ) command="aws ec2 describe-addresses --region \"${aws_region}\" --query 'Addresses[].PublicIp' --filters \"Name=domain,Values=standard\" --output text | wc -l | sed \"s/ //g\"" command_message "${command}" no_ips=$( eval "${command}" ) if [ "${max_ips}" -ne "${no_ips}" ]; then inc_secure "Number of Elastic IPs consumed is less than limit of \"${max_ips}\"" else inc_insecure "Number of Elastic IPs consumed has reached limit of \"${max_ips}\"" fi # Check Instances are using EC2-VPC and not EC2-Classic command="aws ec2 describe-instances --region \"${aws_region}\" --query 'Reservations[*].Instances[*].InstanceId' --output text" command_message "${command}" instances=$( eval "${command}" ) for instance in ${instances}; do command="aws ec2 describe-instances --region \"${aws_region}\" --instance-ids \"${instance}\" --query 'Reservations[*].Instances[*].VpcId' --output text" command_message "${command}" vpc=$( eval "${command}" ) if [ -n "${vpc}" ]; then inc_secure "Instance \"${instance}\" is an EC2-VPC platform" else inc_insecure "Instance \"${instance}\" is an EC2-Classic platform" fi done } ================================================ FILE: modules/aws/compute/audit_aws_rec_elb.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_elb # # Check ELB Recommendations # # Refer to https://www.cloudconformity.com/conformity-rules/ELB/elb-connection-draining-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/ELB/elb-cross-zone-load-balancing-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/ELB/elb-minimum-number-of-ec2-instances.html # Refer to https://www.cloudconformity.com/conformity-rules/ELB/unused-elastic-load-balancers.html #. audit_aws_rec_elb () { print_function "audit_aws_rec_elb" check_message "ELB Recommendations" command="aws elb describe-load-balancers --region \"${aws_region}\" --query \"LoadBalancerDescriptions[].LoadBalancerName\" --output text" command_message "${command}" elbs=$( eval "${command}" ) for elb in ${elbs}; do command="aws elb describe-load-balancer-attributes --region \"${aws_region}\" --load-balancer-name \"${elb}\" --query \"LoadBalancerAttributes.ConnectionDraining\" | grep Enabled | grep true" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_insecure "ELB \"${elb}\" does not have connection draining enabled" verbose_message "aws elb modify-load-balancer-attributes --region \"${aws_region}\" --load-balancer-name \"${elb}\" --load-balancer-attributes \"{\\\"ConnectionDraining\\\":{\\\"Enabled\\\":true, \\\"Timeout\\\":300}}\"" "fix" else inc_secure "ELB \"${elb}\" has connection draining" fi command="aws elb describe-load-balancer-attributes --region \"${aws_region}\" --load-balancer-name \"${elb}\" --query \"LoadBalancerAttributes.CrossZoneLoadBalancing\" | grep Enabled | grep true" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_insecure "ELB \"${elb}\" does not have cross zone balancing enabled" else inc_secure "ELB \"${elb}\" has cross zone balancing enabled" fi command="aws elb describe-instance-health --region \"${aws_region}\" --load-balancer-name \"${elb}\" --query \"InstanceStates[].State\" | grep -c InService" command_message "${command}" number=$( eval "${command}" ) if [ "${number}" -lt 2 ]; then inc_insecure "ELB \"${elb}\" does not have at least 2 instances in service" else inc_secure "ELB \"${elb}\" has at least two instances in service" fi command="aws elb describe-instance-health --region \"${aws_region}\" --load-balancer-name \"${elb}\" --query \"InstanceStates[].InstanceState\" --filter ansible_value=state,Values='OutOfService' --output text" command_message "${command}" instances=$( eval "${command}" ) for instance in ${instances}; do inc_insecure "ELB \"${elb}\" instance \"${instance}\" is out of service " done done } ================================================ FILE: modules/aws/compute/audit_aws_rec_es.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_es # # Check Elasticsearch Recommendations # # Refer to https://www.cloudconformity.com/conformity-rules/Elasticsearch/elasticsearch-dedicated-master-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/Elasticsearch/general-purpose-ssd-volume.html #. audit_aws_rec_es () { print_function "audit_aws_rec_es" check_message "Elasticsearch Recommendations" command="aws es list-domain-names --region \"${aws_region}\" --query \"DomainNames[].DomainName\" --output text" command_message "${command}" domains=$( eval "${command}" ) for domain in ${domains}; do # Check that ES domains have dedicated masters command="aws es describe-elasticsearch-domain --domain-name \"${domain}\" --query \"DomainStatus.ElasticsearchClusterConfig.DedicatedMasterEnabled\" | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Elasticsearch doamin \"${domain}\" has dedicated master nodes" else inc_insecure "Elasticsearch domain \"${domain}\" does not have dedicated master nodes" fi # Check that ES domains are using cost effective storage command="aws es describe-elasticsearch-domain --domain-name \"${domain}\" --query \"DomainStatus.EBSOptions.VolumeType\" | grep \"gp2\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Elasticsearch doamin \"${domain}\" is using General Purpose SSD" else inc_insecure "Elasticsearch domain \"${domain}\" is not using General Purpose SSD" command="aws es describe-elasticsearch-domain --domain-name \"${domain}\" --query \"DomainStatus.EBSOptions.VolumeSize\" --output text" command_message "${command}" vol_size=$( eval "${command}" ) verbose_message "aws es update-elasticsearch-domain-config --region \"${aws_region}\" --domain-name \"${domain}\" --ebs-options EBSEnabled=true,VolumeType=\"gp2\",VolumeSize=$vol_size" "fix" fi # Check that ES domains have cross zone awareness command="aws es describe-elasticsearch-domain --domain-name \"${domain}\" --query \"DomainStatus.ElasticsearchClusterConfig.ZoneAwarenessEnabled\" | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Elasticsearch doamin \"${domain}\" has cross zone awareness" else inc_insecure "Elasticsearch domain \"${domain}\" does not have cross zone awareness" fi done } ================================================ FILE: modules/aws/compute/audit_aws_ses.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_ses # # Check AWS SES # # Refer to https://www.cloudconformity.com/conformity-rules/SES/dkim-enabled.html #. audit_aws_ses () { print_function "audit_aws_ses" check_message "SES" # determine if your AWS Simple Email Service (SES) identities (domains and email addresses) are configured to use DKIM signatures command="aws ses list-identities --region \"${aws_region}\" --query Identities --output text 2> /dev/null" command_message "${command}" domains=$( eval "${command}" ) for domain in ${domains}; do command="aws ses get-identity-dkim-attributes --region \"${aws_region}\" --identities \"${domain}\" | grep DkimEnabled | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Domain \"${domain}\" has DKIM enabled" else inc_insecure "Domain \"${domain}\" does not have DKIM enabled" verbose_message "aws ses set-identity-dkim-enabled --region \"${aws_region}\" --identity \"${domain}\" --dkim-enabled" "fix" fi done } ================================================ FILE: modules/aws/config/audit_aws_cf.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_cf # # Check AWS CloudFormation # # Refer to https://www.cloudconformity.com/conformity-rules/CloudFormation/cloudformation-stack-notification.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudFormation/cloudformation-stack-policy.html #. audit_aws_cf () { # Check Cloud Formation stacks are using SNS print_function "audit_aws_cf" check_message "CloudFormation" command="aws cloudformation list-stacks --region \"${aws_region}\" --query 'StackSummaries[].StackId' --output text" command_message "${command}" stacks=$( eval "${command}" ) for stack in ${stacks}; do command="aws cloudformation describe-stacks --region \"${aws_region}\" --stack-name \"${stack}\" --query 'Stack[].NotificationARNs' --output text" command_message "${command}" check=$( eval "${command}" ) stack=$( echo "${stack}" | cut -f2 -d/ ) if [ "${check}" ]; then inc_secure "SNS topic ${exists} for CloudFormation stack \"${stack}\"" else inc_insecure "SNS topic does not exist for CloudFormation stack \"${stack}\"" fi done # Check stacks have a policy command="aws cloudformation list-stacks --region \"${aws_region}\" --query 'StackSummaries[].StackName' --output text" command_message "${command}" stacks=$( eval "${command}" ) for stack in ${stacks}; do command="aws cloudformation get-stack-policy --region \"${aws_region}\" --stack-name \"${stack}\" --query 'StackPolicyBody' --output text 2> /dev/null" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ]; then inc_secure "CloudFormation stack \"${stack}\" has a policy" else inc_insecure "CloudFormation stack \"${stack}\" does not have a policy" fi done } ================================================ FILE: modules/aws/config/audit_aws_config.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_config # # Check AWS Config # # Refer to https://www.cloudconformity.com/conformity-rules/Config/aws-config-enabled.html #. audit_aws_config () { print_function "audit_aws_config" check_message "Config" command="aws configservice describe-configuration-recorders --region \"${aws_region}\"" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_insecure "AWS Configuration Recorder not enabled" run_lockdown "aws configservice start-configuration-recorder" "Configuration Recorder Service to enabled" else inc_secure "AWS Configuration Recorder enabled" fi command="aws configservice --region \"${aws_region}\" get-status | grep FAILED" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ]; then inc_insecure "AWS Config not enabled" else inc_secure "AWS Config enabled" fi } ================================================ FILE: modules/aws/config/audit_aws_support_role.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_support_role # # Check AWS Support Role # # Refer to Section(s) 1.22 Page(s) 64-5 CIS AWS Foundations Benchmark v1.1.0 #. audit_aws_support_role () { print_function "audit_aws_support_role" check_message "Support" command="aws iam list-policies --query 'Policies[?PolicyName == \"AWSSupportAccess\"]' | grep Arn | awk -F': ' '{print \$2}' | sed \"s/ //g\" | sed \"s/,//g\" | sed \"s/\\\"//g\"" command_message "${command}" arn=$( eval "${command}" ) command="aws iam list-entities-for-policy --policy-arn \"${arn}\" | grep PolicyRoles | cut -f2 -d:" command_message "${command}" roles=$( eval "${command}" ) command="aws iam list-entities-for-policy --policy-arn \"${arn}\" | grep PolicyGroups | cut -f2 -d:" command_message "${command}" groups=$( eval "${command}" ) command="aws iam list-entities-for-policy --policy-arn \"${arn}\" | grep PolicyUsers | cut -f2 -d:" command_message "${command}" users=$( eval "${command}" ) if [ -z "${roles}" ] && [ -z "${users}" ] && [ -z "${groups}" ]; then inc_secure "A support role has been created to manage incidents" else inc_insecure "There is no support role to manage incidents" fi } ================================================ FILE: modules/aws/database/audit_aws_ec.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_ec # # Check AWS ElastiCache # # Refer to https://www.cloudconformity.com/conformity-rules/ElastiCache/elasticache-multi-az.html #. audit_aws_ec () { print_function "audit_aws_ec" check_message "ElastiCache" command="aws elasticache describe-replication-groups --region \"${aws_region}\" --query 'ReplicationGroups[].ReplicationGroupId' --output text" command_message "${command}" caches=$( eval "${command}" ) for cache in ${caches}; do command="aws elasticache describe-replication-groups --region \"${aws_region}\" --replication-group-id \"${cache}\" --query 'ReplicationGroups[].AutomaticFailover' | grep enabled" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "ElastiCache \"${cache}\" is Multi-AZ enabled" else inc_insecure "ElastiCache \"${cache}\" is not Multi-AZ enabled" lock_command="aws elasticache modify-replication-group --region ${aws_region} --replication-group-id ${cache} --automatic-failover-enabled --apply-immediately" lock_message="ElastiCache \"${cache}\" Multi-AZ to enabled" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi done } ================================================ FILE: modules/aws/database/audit_aws_rds.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rds # # Check RDS Recommendations # # Refer to https://www.cloudconformity.com/conformity-rules/RDS/rds-auto-minor-version-upgrade.html # Refer to https://www.cloudconformity.com/conformity-rules/RDS/rds-automated-backups-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/RDS/rds-encryption-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/RDS/rds-publicly-accessible.html # Refer to https://www.cloudconformity.com/conformity-rules/RDS/rds-encrypted-with-kms-customer-master-keys.html # Refer to https://www.cloudconformity.com/conformity-rules/RDS/instance-not-in-public-subnet.html # Refer to https://www.cloudconformity.com/conformity-rules/RDS/rds-master-username.html #. audit_aws_rds () { print_function "audit_aws_rds" check_message "RDS" command="aws rds describe-db-instances --region \"${aws_region}\" --query 'DBInstances[].DBInstanceIdentifier' --output text" command_message "${command}" dbs=$( eval "${command}" ) for db in ${dbs}; do # Check if auto minor version upgrades are enabled command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].AutoMinorVersionUpgrade' | grep true" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ]; then inc_secure "RDS instance \"${db}\" has auto minor version upgrades enabled" else inc_insecure "RDS instance \"${db}\" does not have auto minor version upgrades enabled" fix_message "aws rds modify-db-instance --region \"${aws_region}\" --db-instance-identifier \"${db}\" --auto-minor-version-upgrade --apply-immediately" fi # Check if automated backups are enabled command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].BackupRetentionPeriod' --output text" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" -eq "0" ]; then inc_secure "RDS instance \"${db}\" has automated backups enabled" else inc_insecure "RDS instance \"${db}\" does not have automated backups enabled" fix_message "aws rds modify-db-instance --region \"${aws_region}\" --db-instance-identifier \"${db}\" --backup-retention-period \"${aws_rds_min_retention}\" --apply-immediately" fi # Check if RDS instance is encrypted command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].StorageEncrypted' | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "RDS instance \"${db}\" is encrypted" else inc_insecure "RDS instance \"${db}\" is not encrypted" fi # Check if KMS is being used command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].KmsKeyId' --output text | cut -f2 -d/" command_message "${command}" key_id=$( eval "${command}" ) if [ -n "${key_id}" ]; then inc_secure "RDS instance \"${db}\" is encrypted with a KMS key" else inc_insecure "RDS instance \"${db}\" is not encrypted with a KMS key" fi # Check if RDS instance is publicly accessible command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].PubliclyAccessible' | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_secure "RDS instance \"${db}\" is not publicly accessible" else inc_insecure "RDS instance \"${db}\" is publicly accessible" fi # Check if RDS instance VPC is publicly accessible command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[*].VpcSecurityGroups[].VpcSecurityGroupId' --output text" command_message "${command}" sgs=$( eval "${command}" ) for sg in ${sgs}; do check_aws_open_port "${sg}" "3306" "tcp" "MySQL" "RDS" "${db}" done # Check RDS instance is not on a public subnet command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].DBSubnetGroup.Subnets[].SubnetIdentifier' --output text" command_message "${command}" subnets=$( eval "${command}" ) for subnet in ${subnets}; do command="aws ec2 describe-route-tables --region \"${aws_region}\" --filters \"Name=association.subnet-id,Values=$subnet\" --query 'RouteTables[].Routes[].DestinationCidrBlock' | grep \"0.0.0.0/0\"" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_secure "RDS instance \"${db}\" is not on a public facing subnet" else inc_insecure "RDS instance \"${db}\" is on a public facing subnet" fi done # Check that your Amazon RDS production databases are not using 'awsuser' as master command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].MasterUsername' | grep \"awsuser\"" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_secure "RDS instance \"${db}\" is not using awsuser as master username" else inc_insecure "RDS instance \"${db}\" is using awsuser as master username" fi done } ================================================ FILE: modules/aws/database/audit_aws_rec_dynamodb.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_dynamodb # # Check DynamoDB Recommendations # # Refer to https://www.cloudconformity.com/conformity-rules/DynamoDB/unused-dynamodb-tables.html #. audit_aws_rec_dynamodb () { # Check for zero length tables print_function "audit_aws_rec_dynamodb" check_message "DynamoDB" command="aws dynamodb list-tables --region \"${aws_region}\" --query 'TableNames' --output text" command_message "${command}" tables=$( eval "${command}" ) for table in ${table}s; do command="aws dynamodb describe-table --region \"${aws_region}\" --table-name \"${table}\" --query 'Table.ItemCount' --output text" command_message "${command}" size=$( eval "${command}" ) if [ ! "${size}" -eq 0 ]; then inc_secure "DynamoDB table \"${table}\" is not empty" else inc_insecure "DynamoDB table \"${table}\" is empty" fi done } ================================================ FILE: modules/aws/database/audit_aws_rec_ec.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_ec # # Check ElastiCache Recommendation # # Refer to https://www.cloudconformity.com/conformity-rules/ElastiCache/reserved-cache-nodes-expiration.html #. audit_aws_rec_ec () { print_function "audit_aws_rec_ec" check_message "ElastiCache Recommendation" # Ensure that your AWS ElastiCache Reserved Instances (RIs) are renewed before expiration command="aws elasticache describe-reserved-cache-nodes --region \"${aws_region}\" --query 'ReservedCacheNodes[].ReservedCacheNodeId' --output text" command_message "${command}" caches=$( eval "${command}" ) for cache in ${caches}; do command="aws elasticache describe-reserved-cache-nodes --region \"${aws_region}\" --reserved-cache-node-id \"${cache}\" --query 'ReservedDBInstances[].ReservedCacheNodes' --output text | cut -f1 -d." command_message "${command}" start_date=$( eval "${command}" ) command="aws elasticache describe-reserved-cache-nodes --region \"${aws_region}\" --reserved-cache-node-id \"${cache}\" --query 'ReservedDBInstances[].Duration' --output text" command_message "${command}" dur_secs=$( eval "${command}" ) curr_secs=$( date "+%s" ) if [ "${os_name}" = "Linux" ]; then command="date -d \"${start_date}\" \"+%s\"" command_message "${command}" start_secs=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%SS\" \"${start_date}\" \"+%s\"" command_message "${command}" start_secs=$( eval "${command}" ) fi command="echo \"(${start_secs} + ${dur_secs})\" | bc" command_message "${command}" exp_secs=$( eval "${command}" ) command="echo \"(7 * 84600)\" |bc" command_message "${command}" test_secs=$( eval "${command}" ) command="echo \"(${exp_secs} - ${curr_secs})\" | bc" command_message "${command}" left_secs=$( eval "${command}" ) if [ "${left_secs}" -lt "${test_secs}" ]; then inc_secure "Reserved ElastiCache instance \"${cache}\" has more than 7 days remaining" else inc_insecure "Reserved ElastiCache instance \"${cache}\" has less than 7 days remaining" fi done } ================================================ FILE: modules/aws/database/audit_aws_rec_rds.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_rds # # Check RDS recommendations # # Refer to https://www.cloudconformity.com/conformity-rules/RDS/rds-multi-az.html # Refer to https://www.cloudconformity.com/conformity-rules/RDS/general-purpose-ssd-storage-type.html # Refer to https://www.cloudconformity.com/conformity-rules/RDS/reserved-instance-expiration.html # Refer to https://www.cloudconformity.com/conformity-rules/RDS/rds-sufficient-backup-retention-period.html #. audit_aws_rec_rds () { print_function "audit_aws_rec_rds" check_message "RDS Recommendations" command="aws rds describe-db-instances --region \"${aws_region}\" --query 'DBInstances[].DBInstanceIdentifier' --output text" command_message "${command}" dbs=$( eval "${command}" ) for db in ${dbs}; do # Check if database is Multi-AZ command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].MultiAZ' | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "RDS instance \"${db}\" is Multi-AZ enabled" else inc_insecure "RDS instance \"${db}\" is not Multi-AZ enabled" verbose_message "aws rds modify-db-instance --region ${aws_region} --db-instance-identifier ${db} --multi-az --apply-immediately" "fix" fi # Check that EC2 volumes are using cost effective storage command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].StorageType' |grep \"gp2\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" = "available" ]; then inc_secure "RDS instance \"${db}\" is using General Purpose SSD" else inc_insecure "RDS instance \"${db}\" is not using General Purpose SSD" fi # Check backup retention period is at least 7 days command="aws rds describe-db-instances --region \"${aws_region}\" --db-instance-identifier \"${db}\" --query 'DBInstances[].BackupRetentionPeriod' --output text" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" -lt "$aws_rds_min_retention" ]; then inc_secure "RDS instance \"${db}\" has a retention period greater than \"$aws_rds_min_retention\"" else inc_insecure "RDS instance \"${db}\" has a retention period less than \"$aws_rds_min_retention\"" fi done # Ensure that your AWS RDS Reserved Instances (RIs) are renewed before expiration command="aws rds describe-reserved-db-instances --region \"${aws_region}\" --query 'ReservedDBInstances[].ReservedDBInstanceId' --output text" command_message "${command}" dbs=$( eval "${command}" ) for db in ${dbs}; do command="aws rds describe-reserved-db-instances --region \"${aws_region}\" --reserved-db-instance-id \"${db}\" --query 'ReservedDBInstances[].StartTime' --output text |cut -f1 -d. " command_message "${command}" start_date=$( eval "${command}" ) command="aws rds describe-reserved-db-instances --region \"${aws_region}\" --reserved-db-instance-id \"${db}\" --query 'ReservedDBInstances[].Duration' --output text" command_message "${command}" dur_secs=$( eval "${command}" ) command="date \"+%s\"" command_message "${command}" curr_secs=$( eval "${command}" ) if [ "${os_name}" = "Linux" ]; then command="date -d \"${start_date}\" \"+%s\"" command_message "${command}" start_secs=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%SS\" \"${start_date}\" \"+%s\"" command_message "${command}" start_secs=$( eval "${command}" ) fi command="echo \"(${start_secs} + ${dur_secs})\" | bc" command_message "${command}" exp_secs=$( eval "${command}" ) command="echo \"(7 * 84600)\" | bc" command_message "${command}" test_secs=$( eval "${command}" ) command="echo \"(${exp_secs} - ${curr_secs})\" | bc" command_message "${command}" left_secs=$( eval "${command}" ) if [ "${left_secs}" -lt "${test_secs}" ]; then inc_secure "Reserved RDS instance \"${db}\" has more than 7 days remaining" else inc_insecure "Reserved RDS instance \"${db}\" has less than 7 days remaining" fi done } ================================================ FILE: modules/aws/database/audit_aws_rec_redshift.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_redshift # # Check AWS Redshift recommendations # # Refer to https://www.cloudconformity.com/conformity-rules/Redshift/reserved-nodes-expiration.html #. audit_aws_rec_redshift () { print_function "audit_aws_rec_redshift" check_message "Redshift Recommendations" command="aws redshift describe-reserved-nodes --region \"${aws_region}\" --query 'ReservedNodes[].ReservedNodeId' --output text" command_message "${command}" dbs=$( eval "${command}" ) for db in ${dbs}; do command="aws redshift describe-reserved-nodes --region \"${aws_region}\" --reserved-node-id \"${dir_name}\" --query 'ReservedNodes[].StartTime' --output text | cut -f1 -d. " command_message "${command}" start_date=$( eval "${command}" ) command="aws redshift describe-reserved-nodes --region \"${aws_region}\" --reserved-node-id \"${db}\" --query 'ReservedNodes[].Duration' --output text" command_message "${command}" dur_secs=$( eval "${command}" ) command="date \"+%s\"" command_message "${command}" curr_secs=$( eval "${command}" ) if [ "${os_name}" = "Linux" ]; then command="date -d \"${start_date}\" \"+%s\"" command_message "${command}" start_secs=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%SS\" \"${start_date}\" \"+%s\"" command_message "${command}" start_secs=$( eval "${command}" ) fi command="echo \"(${start_secs} + ${dur_secs})\" | bc" command_message "${command}" exp_secs=$( eval "${command}" ) command="echo \"(7 * 84600)\" | bc" command_message "${command}" test_secs=$( eval "${command}" ) command="echo \"(${exp_secs} - ${curr_secs})\" | bc" command_message "${command}" left_secs=$( eval "${command}" ) if [ "${left_secs}" -lt "${test_secs}" ]; then inc_secure "Reserved Redshift instance \"${db}\" has more than 7 days remaining" else inc_insecure "Reserved Redshift instance \"${db}\" has less than 7 days remaining" fi done } ================================================ FILE: modules/aws/database/audit_aws_redshift.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_redshift # # Check AWS Redshift # # Refer to https://www.cloudconformity.com/conformity-rules/Redshift/cluster-allow-version-upgrade.html # Refer to https://www.cloudconformity.com/conformity-rules/Redshift/redshift-cluster-audit-logging-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/Redshift/redshift-cluster-encrypted.html # Refer to https://www.cloudconformity.com/conformity-rules/Redshift/redshift-cluster-encrypted-with-kms-customer-master-keys.html # Refer to https://www.cloudconformity.com/conformity-rules/Redshift/redshift-cluster-in-vpc.html # Refer to https://www.cloudconformity.com/conformity-rules/Redshift/redshift-parameter-groups-require-ssl.html # Refer to https://www.cloudconformity.com/conformity-rules/Redshift/redshift-cluster-publicly-accessible.html #. audit_aws_redshift () { print_function "audit_aws_redshift" check_message "Redshift" command="aws redshift describe-clusters --region \"${aws_region}\" --query 'Clusters[].ClusterIdentifier' --output text" command_message "${command}" dbs=$( eval "${command}" ) for db in ${dbs}; do # Check if version upgrades are enabled command="aws redshift describe-clusters --region \"${aws_region}\" --cluster-identifier \"${db}\" --query 'Clusters[].AllowVersionUpgrade' | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Redshift instance \"${db}\" has version upgrades enabled" else inc_insecure "Redshift instance \"${db}\" does not have version upgrades enabled" verbose_message "aws redshift modify-cluster --region \"${aws_region}\" --cluster-identifier \"${db}\" --allow-version-upgrade" "fix" fi # Check if audit logging is enabled command="aws redshift describe-logging-status --region \"${aws_region}\" --cluster-identifier \"${db}\" | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Redshift instance \"${db}\" has logging enabled" else inc_insecure "Redshift instance \"${db}\" does not have logging enabled" verbose_message "aws redshift enable-logging --region \"${aws_region}\" --cluster-identifier \"${db}\" --bucket-name " "fix" fi # Check if encryption is enabled command="aws redshift describe-logging-status --region \"${aws_region}\" --cluster-identifier \"${db}\" --query 'Clusters[].Encrypted' | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Redshift instance \"${db}\" has encryption enabled" else inc_insecure "Redshift instance \"${db}\" does not have encryption enabled" fi # Check if KMS keys are being used command="aws redshift describe-logging-status --region \"${aws_region}\" --cluster-identifier \"${db}\" --query 'Clusters[].[Encrypted,KmsKeyId]' | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Redshift instance \"${db}\" is using KMS keys" else inc_insecure "Redshift instance \"${db}\" is not using KMS keys" fi # Check if EC2-VPC platform is being used rather than EC2-Classic command="aws redshift describe-logging-status --region \"${aws_region}\" --cluster-identifier \"${db}\" --query 'Clusters[].VpcId' --output text" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Redshift instance \"${db}\" is using the EC2-VPC platform" else inc_insecure "Redshift instance \"${db}\" may be using the EC2-Classic platform" fi # Check that parameter groups require SSL command="aws redshift describe-logging-status --region \"${aws_region}\" --cluster-identifier \"${db}\" --query 'Clusters[].ClusterParameterGroups[].ParameterGroupName[]' --output text" command_message "${command}" groups=$( eval "${command}" ) for group in ${groups}; do command="aws redshift describe-cluster-parameters --region \"${aws_region}\" --parameter-group-name \"${group}\" --query 'Parameters[].Description' | grep -i ssl" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Redshift instance \"${db}\" parameter group \"$group\" is using SSL" else inc_insecure "Redshift instance \"${db}\" parameter group \"$group\" is not using SSL" fi done # Check if Redshift is publicly available command="aws redshift describe-clusters --region \"${aws_region}\" --cluster-identifier \"${db}\" --query 'Clusters[].PubliclyAccessible' | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_secure "Redshift instance \"${db}\" is not publicly available" else inc_insecure "Redshift instance \"${db}\" is publicly available" fi done } ================================================ FILE: modules/aws/logging/audit_aws_inspector.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_inspector # # Check AWS Inspector # # Refer to https://docs.aws.amazon.com/inspector/latest/userguide/inspector_introduction.html #. audit_aws_inspector () { # check for templates print_function "audit_aws_inspector" check_message "Inspector" command="aws inspector list-assessment-templates 2> /dev/null --output text" command_message "${command}" templates=$( eval "${command}" ) if [ -n "${templates}" ]; then # check for subscriptions to templates command="aws inspector list-event-subscriptions --region \"${aws_region}\" --query subscriptions --output text" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ]; then inc_secure "Inspectors have subscriptions" else inc_insecure "Inspectors do not have subscriptions" fi for template in ${templates}; do command="aws inspector describe-assessment-templates --region \"${aws_region}\" --assessment-template-arns \"${template}\" --query 'assessmentTemplates[].name' --output text" command_message "${command}" names=$( eval "${command}" ) for name in ${ansible_value}s; do command="aws ec2 describe-instances --region \"${aws_region}\" --query 'Reservations[].Instances[].InstanceId' --output text" command_message "${command}" instances=$( eval "${command}" ) for instance in ${instances}; do command="aws ec2 describe-instances --region \"${aws_region}\" --instance-id \"${instance}\" --query 'Reservations[].Instances[].Tags' | grep \"${ansible_value}\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Instance \"${instance}\" has an inspector tag" else inc_insecure "Instance \"${instance}\" does not have an inspector tag" fi done done done else inc_insecure "No inspector templates exist" fi } ================================================ FILE: modules/aws/logging/audit_aws_logging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_logging # # Check AWS Logging # # Refer to Section(s) 2.1 Page(s) 70-1 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 2.2 Page(s) 72-3 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 2.3 Page(s) 74-5 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 2.4 Page(s) 76-7 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 2.6 Page(s) 81-2 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 2.7 Page(s) 83-4 CIS AWS Foundations Benchmark v1.1.0 # # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-s3-bucket-logging-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-bucket-mfa-delete-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-bucket-publicly-accessible.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-global-services-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-integrated-with-cloudwatch.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-log-file-integrity-validation.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-bucket-publicly-accessible.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-s3-bucket-logging-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudTrail/cloudtrail-global-services-logging-duplicated.html #. audit_aws_logging () { print_function "audit_aws_logging" check_message "CloudTrail" command="aws cloudtrail describe-trails --region \"${aws_region}\" --query \"trailList[].Name\" --output text" command_message "${command}" trails=$( eval "${command}" ) if [ "${trails}" ]; then for trail in ${trails}; do # Check CloudTrail has MultiRegion enabled command="aws cloudtrail describe-trails --region \"${aws_region}\" --trail-name-list \"${trail}\" --query \"trailList[].IsMultiRegionTrail\" | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "CloudTrail \"${trail}\" is enabled in all regions" else inc_insecure "CloudTrail \"${trail}\" is not enabled in all regions" verbose_message "aws cloudtrail update-trail --name ${trail} --is-multi-region-trail" fix fi # Check CloudTrail is recording global events command="aws cloudtrail describe-trails --region \"${aws_region}\" --trail-name-list \"${trail}\" --query \"trailList[].IncludeGlobalServiceEvents\" | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "CloudTrail \"${trail}\" is recording global events" else inc_insecure "CloudTrail \"${trail}\" is not recording global events" verbose_message "aws cloudtrail update-trail --name ${trail} --include-global-service-events" fix fi # Check log file validation is enabled command="aws cloudtrail describe-trails --region \"${aws_region}\" --trail-name-list \"${trail}\" --query \"trailList[].LogFileValidationEnabled\" | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "CloudTrail \"${trail}\" log file validation is enabled" else inc_insecure "CloudTrail \"${trail}\" log file validation is not enabled" verbose_message "aws cloudtrail update-trail --region ${aws_region} --name ${trail} --enable-log-file-validation" fix fi # done command="aws cloudtrail describe-trails --region \"${aws_region}\" --query 'trailList[*].S3BucketName' --output text" command_message "${command}" buckets=$( eval "${command}" ) # Check that CloudTrail buckets don't grant access to users it shouldn't # Check that CloudTrail bucket versioning is enable for bucket in ${buckets}; do command="aws s3api get-bucket-acl --region \"${aws_region}\" --bucket \"${bucket}\" | grep URI | grep AllUsers" command_message "${command}" grants=$( eval "${command}" ) if [ -n "${grants}" ]; then inc_insecure "CloudTrail log file bucket \"${bucket}\" grants access to Principal AllUsers" else inc_secure "CloudTrail log file bucket \"${bucket}\" does not grant access to Principal AllUsers" fi command="aws s3api get-bucket-acl --region \"${aws_region}\" --bucket \"${bucket}\" | grep URI | grep AuthenticatedUsers" command_message "${command}" grants=$( eval "${command}" ) if [ -n "${grants}" ]; then inc_insecure "CloudTrail log file bucket ${bucket} grants access to Principal AuthenticatedUsers" verbose_message "aws s3api put-bucket-acl --region ${aws_region} --region ${aws_region}--bucket ${bucket} --acl private" fix else inc_secure "CloudTrail log file bucket ${bucket} does not grant access to Principal AuthenticatedUsers" fi command="aws s3api get-bucket-policy --region \"${aws_region}\" --bucket \"${bucket}\" --query Policy | tr \"}\" \"\\\n\" | grep Allow | grep \"\*\"" command_message "${command}" grants=$( eval "${command}" ) if [ -n "${grants}" ]; then inc_insecure "CloudTrail log file bucket \"${bucket}\" grants access to Principal *" else inc_secure "CloudTrail log file bucket \"${bucket}\" does not grant access to Principal *" fi command="aws s3api get-bucket-logging --region \"${aws_region}\" --bucket \"${bucket}\"" command_message "${command}" logging=$( eval "${command}" ) if [ -z "$logging" ]; then inc_insecure "CloudTrail log file bucket ${bucket} does not have access logging enabled" verbose_message "aws s3api put-bucket-acl --region ${aws_region} --bucket ${bucket} --grant-write URI=http://acs.amazonaws.com/groups/s3/LogDelivery --grant-read-acp URI=http://acs.amazonaws.com/groups/s3/LogDelivery" fix verbose_message "cd aws ; aws s3api put-bucket-logging --region ${aws_region} --bucket ${bucket} --bucket-logging-status file://server-access-logging.json" else inc_secure "CloudTrail log file bucket ${bucket} has access logging enabled" fi command="aws s3api get-bucket-versioning --bucket \"${bucket}\" | grep Enabled" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "CloudTrail log bucket \"${bucket}\" has versioning enabled" else inc_insecure "CloudTrail bucket \"${bucket}\" does not have versioning enabled" fi done command="aws cloudtrail describe-trails --region \"${aws_region}\" --query trailList[].Name --output text" command_message "${command}" trails=$( eval "${command}" ) for trail in ${trails}; do # Check CloudTrail has a CloudWatch Logs group enabled command="aws cloudtrail describe-trails --region \"${aws_region}\" --trail-name-list \"${trail}\" |grep CloudWatchLogsLogGroupArn" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_insecure "CloudTrail ${trail} does not have a CloudWatch Logs group enabled" else inc_secure "CloudTrail ${trail} has a CloudWatch Logs group enabled" fi # Check CloudTrail bucket is receiving logs command="aws cloudtrail get-trail-status --region \"${aws_region}\" --name \"${bucket}\" --query \"LatestCloudWatchLogsDeliveryTime\" --output text" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_insecure "CloudTrail \"${trail}\" does not have a Last log file delivered timestamp" else inc_secure "CloudTrail \"${trail}\" has a last log file delivered timestamp" fi # Check CloudTrail has key enabled for bucket command="aws cloudtrail get-trail-status --region \"${aws_region}\" --name \"${bucket}\" | grep KmsKeyId" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_insecure "CloudTrail \"${trail}\" does not have a KMS Key ID" else inc_secure "CloudTrail \"${trail}\" has a KMS Key ID" fi done else inc_insecure "CloudTrail is not enabled" fi } ================================================ FILE: modules/aws/logging/audit_aws_monitoring.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_monitoring # # Check AWS monitoring # # Refer to Section(s) 3.1 Page(s) 87-9 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.2 Page(s) 90-2 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.3 Page(s) 93-6 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.4 Page(s) 97-9 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.5 Page(s) 100-2 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.6 Page(s) 103-5 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.7 Page(s) 106-7 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.8 Page(s) 108-10 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.9 Page(s) 111-3 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.10 Page(s) 114-6 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.11 Page(s) 117-9 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.12 Page(s) 120-2 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.13 Page(s) 123-5 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 3.14 Page(s) 126-8 CIS AWS Foundations Benchmark v1.1.0 # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/aws-config-changes-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/authorization-failures-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/cmk-disabled-or-scheduled-for-deletion-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/cloudtrail-changes-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/console-sign-in-failures-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/ec2-instance-changes-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/iam-policy-changes-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/internet-gateway-changes-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/network-acl-changes-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/root-account-usage-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/route-table-changes-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/s3-bucket-changes-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/securitygroup-changes-alarm.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/vpc-changes-alarm.html #. audit_aws_monitoring () { print_function "audit_aws_monitoring" check_message "CloudWatch" command="aws cloudtrail describe-trails --region \"${aws_region}\" --query \"trailList[].CloudWatchLogsLogGroupArn\" --output text | awk -F':' '{print \$7}'" command_message "${command}" trails=$( eval "${command}" ) if [ "${trails}" ]; then inc_secure "CloudWatch log groups exits for CloudTrail" for trail in ${trails}; do command="aws logs describe-metric-filters --region \"${aws_region}\" --log-group-name \"${trail}\" --query \"metricFilters[].filterPattern\" --output text" command_message "${command}" metrics=$( eval "${command}" ) if [ ! "${metric}" ]; then inc_insecure "CloudWatch log group ${trail} has no metrics" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name unauthorized-api-calls-metric --metric-transformations metricName=unauthorized-api-calls-metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.errorCode = \"*UnauthorizedOperation\") || ($.errorCode = \"AccessDenied*\") }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name no_mfa_console_signin_metric --metric-transformations metricName=no_mfa_console_signin_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = \"ConsoleLogin\") && ($.additionalEventData.MFAUsed != \"Yes\") }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name root_usage_metric --metric-transformations metricName=root_usage_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ $.userIdentity.type = \"Root\" && $.userIdentity.invokedBy NOT ${exists} && $.eventType != \"AwsServiceEvent\" }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name iam_changes_metric --metric-transformations metricName=iam_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name cloudtrail_config_changes_metric --metric-transformations metricName=cloudtrail_cfg_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) ||($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name console_signin_failure_metric --metric-transformations metricName=console_signin_failure_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = ConsoleLogin) && ($.errorMessage = \"Failedauthentication\") }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name disable_or_delete_cmk_metric --metric-transformations metricName=disable_or_delete_cmk_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{($.eventSource = kms.amazonaws.com) && (($.eventName=DisableKey)||($.eventName=ScheduleKeyDeletion))}'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name s3_bucket_policy_changes_metric --metric-transformations metricName=s3_bucket_policy_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventSource = s3.amazonaws.com) && (($.eventName = PutBucketAcl) || ($.eventName = PutBucketPolicy) || ($.eventName = PutBucketCors) || ($.eventName = PutBucketLifecycle) || ($.eventName = PutBucketReplication) || ($.eventName = DeleteBucketPolicy) || ($.eventName = DeleteBucketCors) || ($.eventName = DeleteBucketLifecycle) || ($.eventName = DeleteBucketReplication)) }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name aws_config_changes_metric --metric-transformations metricName=aws_config_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{($.eventSource = config.amazonaws.com) && (($.eventName=StopConfigurationRecorder)||($.eventName=DeleteDeliveryChannel)||($.eventName=PutDeliveryChannel)||($.eventName=PutConfigurationRecorder))}'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name nacl_changes_metric --metric-transformations metricName=nacl_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry) || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry) || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation) }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name security_group_changes_metric --metric-transformations metricName=security_group_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.event Name = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup)}'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name network_gateway_changes_metric --metric-transformations metricName=network_gw_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway) || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway) || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway) }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name route_table_changes_metric --metric-transformations metricName=route_table_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name vpc_changes_metric --metric-transformations metricName=vpc_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }'" "fix" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name ec2_changes_metric --metric-transformations metricName=ec2_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = RunInstances) || ($.eventName = RebootInstances) || ($.eventName = StartInstances) || ($.eventName = StopInstances) || ($.eventName = TerminateInstances) }'" "fix" for sns_topic in unauthorized-api-calls no_mfa_console_signin root_usage iam_changes cloudtrail_config_changes console_signin_failure disable_or_delete_cmk \ s3_bucket_policy_changes aws_config_changes nacl_changes security_group network_gateway route_table_changes vpc_changes ec2_changes; do verbose_message "aws sns create-topic --region ${aws_region} --name ${sns_topic}" "fix" verbose_message "aws sns subscribe --region ${aws_region} --topic-arn ${sns_topic} --protocol $sns_protocol notification-endpoint $sns_endpoints" "fix" done else for metric in UnauthorizedOperation AccessDenied ConsoleLogin additionalEventData.MFAUsed userIdentity.invokedBy AwsServiceEvent \ DeleteGroupPolicy DeleteRolePolicy DeleteUserPolicy PutGroupPolicy PutRolePolicy PutUserPolicy CreatePolicy \ DeletePolicy CreatePolicyVersion DeletePolicyVersion AttachRolePolicy DetachRolePolicy AttachUserPolicy \ DetachUserPolicy AttachGroupPolicy DetachGroupPolicy CreateTrail UpdateTrail DeleteTrail StartLogging StopLogging \ Failedauthentication DisableKey ScheduleKeyDeletion PutBucketAcl PutBucketPolicy PutBucketCors PutBucketLifecycle \ PutBucketReplication DeleteBucketPolicy DeleteBucketCors DeleteBucketLifecycle DeleteBucketReplication \ StopConfigurationRecorder DeleteDeliveryChannel PutDeliveryChannel PutConfigurationRecorder AuthorizeSecurityGroupIngress \ AuthorizeSecurityGroupEgress RevokeSecurityGroupIngress RevokeSecurityGroupEgress CreateSecurityGroup DeleteSecurityGroup \ CreateNetworkAcl CreateNetworkAclEntry DeleteNetworkAcl DeleteNetworkAclEntry ReplaceNetworkAclEntry ReplaceNetworkAclAssociation \ CreateCustomerGateway DeleteCustomerGateway AttachInternetGateway CreateInternetGateway DeleteInternetGateway DetachInternetGateway \ CreateRoute CreateRouteTable ReplaceRoute ReplaceRouteTableAssociation DeleteRouteTable DeleteRoute DisassociateRouteTable \ CreateVpc DeleteVpc ModifyVpcAttribute AcceptVpcPeeringConnection CreateVpcPeeringConnection DeleteVpcPeeringConnection \ RejectVpcPeeringConnection AttachClassicLinkVpc DetachClassicLinkVpc DisableVpcClassicLink EnableVpcClassicLink \ TerminateInstances StopInstances StartInstances RebootInstances RunInstances; do command="aws logs describe-metric-filters --region \"${aws_region}\" --log-group-name \"${trail}\" --query \"metricFilters[].filterPattern\" --output text |grep \"${metric}\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "CloudWatch log group \"${trail}\" metrics include \"${metric}\"" else inc_insecure "CloudWatch log groups \"${trail}\" metrics do not include \"${metric}\"" fi done fi done else inc_insecure "No CloudWatch log groups exist for CloudTrail" fi command="aws cloudwatch describe-alarms --region \"${aws_region}\" --query \"MetricAlarms[].AlarmActions\" --output text" command_message "${command}" alarms=$( eval "${command}" ) if [ "${alarms}" ]; then inc_secure "CloudWatch alarms exits for CloudTrail" for alarm in ${alarms}; do command="aws sns list-subscriptions-by-topic --region \"${aws_region}\" --topic-arn \"${alarm}\" --output text" command_message "${command}" subscribers=$( eval "${command}" ) if [ "${subscribers}" ]; then inc_secure "CloudWatch alarm \"${alarm}\" has subscribers" else inc_insecure "CloudWatch alarm \"${alarm}\" does not have subscribers" fi done else inc_insecure "No CloudWatch alarms exist for CloudTrail" fi } ================================================ FILE: modules/aws/logging/audit_aws_rec_inspector.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_inspector # # Check Inspector Recommendations # # Refer to https://docs.aws.amazon.com/inspector/latest/userguide/inspector_introduction.html #. audit_aws_rec_inspector () { print_function "audit_aws_rec_inspector" check_message "Inspector Recommendations" # check for templates command="aws inspector list-assessment-templates 2> /dev/null --output text" command_message "${command}" templates=$( eval "${command}" ) if [ -n "${templates}" ]; then # Check for CVEs in assessments command="aws inspector list-assessment-runs --region \"${aws_region}\" --output text" command_message "${command}" assessments=$( eval "${command}" ) if [ "${assessments}" ]; then command="aws inspector list-findings --query nextToken --output text | grep -v None" command_message "${command}" token=$( eval "${command}" ) command="aws inspector list-findings --query findingArns --output text | grep -v None" command_message "${command}" findings=$( eval "${command}" ) for finding in ${findings}; do command="aws inspector describe-findings --finding-arns \"${finding}\" --query findings[].attributes[?key==\\\`INSTANCE_ID\\\`].value --output text" command_message "${command}" instance=$( eval "${command}" ) command="aws inspector describe-findings --finding-arns \"${finding}\" --query findings[].attributes[?key==\\\`CVE_ID\\\`].value --output text" command_message "${command}" cve_id=$( eval "${command}" ) if [ "${cve_id}" ]; then inc_insecure "Instance \"${instance}\" is vulnerable to \"${cve_id}\"" fi done if [ -n "${token}" ]; then while [ "${token}" ] ; do command="aws inspector list-findings --next-token \"${token}\" --query findingArns --output text |grep -v None" command_message "${command}" findings=$( eval "${command}" ) for finding in ${findings}; do command="aws inspector describe-findings --finding-arns \"${finding}\" --query findings[].attributes[?key==\\\`INSTANCE_ID\\\`].value --output text" command_message "${command}" instance=$( eval "${command}" ) command="aws inspector describe-findings --finding-arns \"${finding}\" --query findings[].attributes[?key==\\\`CVE_ID\\\`].value --output text" command_message "${command}" cve_id=$( eval "${command}" ) if [ "${cve_id}" ]; then inc_insecure "Instance \"${instance}\" is vulnerable to \"${cve_id}\"" fi done command="aws inspector list-findings --next-token \"${token}\" --query nextToken --output text |grep -v None" command_message "${command}" token=$( eval "${command}" ) done fi fi else inc_insecure "No inspector templates exist" fi } ================================================ FILE: modules/aws/logging/audit_aws_rec_monitoring.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_monitoring # # Check CloudWatch Recommendations # # Refer to https://www.cloudconformity.com/conformity-rules/CloudWatchLogs/ec2-large-instance-changes-alarm.html #. audit_aws_rec_monitoring () { print_function "audit_aws_rec_monitoring" check_message "CloudWatch Recommendations" command="aws cloudtrail describe-trails --region \"${aws_region}\" --query \"trailList[].CloudWatchLogsLogGroupArn\" --output text |awk -F':' '{print \$7}'" command_message "${command}" trails=$( eval "${command}" ) if [ "${trails}" ]; then inc_secure "CloudWatch log groups exits for CloudTrail" for trail in ${trails}; do command="aws logs describe-metric-filters --region \"${aws_region}\" --log-group-name \"${trail}\" --query \"metricFilters[].filterPattern\" --output text" command_message "${command}" metrics=$( eval "${command}" ) if [ -z "${metrics}" ]; then inc_insecure "CloudWatch log group \"${trail}\" has no metrics" verbose_message "aws logs put-metric-filter --region ${aws_region} --log-group-name ${trail} --filter-name ec2_size_changes_metric --metric-transformations metricName=ec2_size_changes_metric,metricNamespace='Audit',metricValue=1 --filter-pattern '{ ($.eventName = RunInstances) && (($.requestParameters.instanceType = *.8xlarge) || ($.requestParameters.instanceType = *.4xlarge)) }'" "fix" # for sns_topic in ec2_size_changes; do # verbose_message "aws sns create-topic --region ${aws_region} --name ${sns_topic}" fix # verbose_message "aws sns subscribe --region ${aws_region} --topic-arn ${sns_topic} --protocol $sns_protocol notification-endpoint $sns_endpoints" fix # done else for metric in RunInstances instanceType ; do command="aws logs describe-metric-filters --region \"${aws_region}\" --log-group-name \"${trail}\" --query \"metricFilters[].filterPattern\" --output text | grep \"${metric}\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "CloudWatch log group \"${trail}\" metrics include \"${metric}\"" else inc_insecure "CloudWatch log groups \"${trail}\" metrics do not include \"${metric}\"" fi done fi done else inc_insecure "No CloudWatch log groups exist for CloudTrail" fi } ================================================ FILE: modules/aws/logging/audit_aws_sns.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_sns # # Check AWS SNS # # Refer to Section(s) 3.15 Page(s) 129-30 CIS AWS Foundations Benchmark v1.1.0 # # Refer to https://www.cloudconformity.com/conformity-rules/SNS/sns-topic-exposed.html #. audit_aws_sns () { print_function "audit_aws_sns" check_message "SNS" command="aws sns list-topics --region \"${aws_region}\" --query 'Topics[].TopicArn' --output text" command_message "${command}" topic_list=$( eval "${command}" ) for topic in ${topic_list}; do # Check SNS topics have subscribers command="aws sns list-subscriptions-by-topic --region \"${aws_region}\" --topic-arn \"${topic}\" --output text" command_message "${command}" subscribers=$( eval "${command}" ) if [ -z "${subscribers}" ]; then inc_insecure "SNS topic \"${topic}\" has no subscribers" else inc_secure "SNS topic has subscribers, review subscribers" fi #check SNS topics are not publicly accessible command="aws sns get-topic-attributes --region \"${aws_region}\" --topic-arn \"${topic}\" --query 'Attributes.Policy' |grep -E \"\*|{\\\"AWS\\\":\\\"\*\\\"}\"" command_message "${command}" sns_check=$( eval "${command}" ) if [ -n "${sns_check}" ]; then inc_insecure "SNS topic \"${topic}\" is publicly accessible" else inc_secure "SNS topic is not publicly accessible" fi done } ================================================ FILE: modules/aws/network/audit_aws_dns.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_dns # # Check AWS DNS # # Refer to https://www.cloudconformity.com/conformity-rules/Route53/route-53-domain-auto-renew.html # Refer to https://www.cloudconformity.com/conformity-rules/Route53/route-53-domain-expired.html # Refer to https://www.cloudconformity.com/conformity-rules/Route53/sender-policy-framework-record-present.html # Refer to https://www.cloudconformity.com/conformity-rules/Route53/route-53-domain-transfer-lock.html #. audit_aws_dns () { print_function "audit_aws_dns" check_message "Route53" command="aws route53domains list-domains --query 'Domains[].DomainName' --output text 2> /dev/null" command_message "${command}" domains=$( eval "${command}" ) for domain in ${domains}; do command="aws route53domains get-domain-detail --domain-name \"${domain}\" | grep true" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_insecure "Domain ${domain} does not auto renew" lock_command="aws route53domains enable-domain-auto-renew --domain-name ${domain}" lock_message="Auto-Renew on Domain \"${domain}\" to enabled" run_lockdown "${lock_command}" "${lock_message}" "sudo" else inc_secure "Domain \"${domain}\" auto renews" fi command="date \"+%s\"" command_message "${command}" cur_secs=$( eval "${command}" ) command="aws route53domains get-domain-detail --domain-name \"${domain}\" --query \"ExpirationDate\" --output text 2> /dev/null" command_message "${command}" exp_secs=$( eval "${command}" ) if [ "${exp_secs}" -lt "${cur_secs}" ]; then inc_insecure "Warning: Domain \"${domain}\" registration has expired" else inc_secure "Domain \"${domain}\" registration has not expired" fi command="aws route53domains get-domain-detail --domain-name \"${domain}\" --query \"Status\" --output text 2> /dev/null | grep clientTransferProhibited" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Domain \"${domain}\" has Domain Transfer Lock enabled" else inc_insecure "Domain \"${domain}\" does not have Domain Transfer Lock enabled" fi done command="aws route53 list-hosted-zones --query \"HostedZones[].Id\" --output text 2> /dev/null | cut -f3 -d'/'" command_message "${command}" zones=$( eval "${command}" ) for zone in ${zones}; do command="aws route53 list-resource-record-sets --hosted-zone-id \"${zone}\" --query \"ResourceRecordSets[?Type == 'SPF']\" --output text" command_message "${command}" spf=$( eval "${command}" ) if [ -n "${spf}" ]; then inc_secure "Zone \"${zone}\" has SPF records" else inc_insecure "Zone \"${zone}\" does not have SPF records" fi done } ================================================ FILE: modules/aws/network/audit_aws_rec_vpcs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_rec_vpcs # # Check AWS VPC recommendations # # Refer to https://www.cloudconformity.com/conformity-rules/VPC/vpc-naming-conventions.html # Refer to https://www.cloudconformity.com/conformity-rules/VPC/vpn-tunnel-redundancy.html #. audit_aws_rec_vpcs () { print_function "audit_aws_rec_vpcs" check_message "VPC Recommendations" # Check Security Groups have Name tags command="aws ec2 describe-vpcs --region \"${aws_region}\" --query 'Vpcs[].VpcId' --output text" command_message "${command}" vpcs=$( eval "${command}" ) for vpc in ${vpcs}; do if [ ! "${vpc}" = "default" ]; then command="aws ec2 describe-vpcs --region \"${aws_region}\" --vpc-ids \"${vpcs}\" --query \"Vpcs[].Tags[?Key==\\\`Name\\\`].Value\" 2> /dev/null --output text" command_message "${command}" ansible_value=$( eval "${command}" ) if [ -z "${ansible_value}" ]; then inc_insecure "AWS VPC ${vpc} does not have a Name tag" verbose_message "aws ec2 create-tags --region ${aws_region} --resources ${image} --tags Key=Name,Value=" "fix" else if [ "${strict_valid_names}" = "y" ]; then command="echo \"${ansible_value}\" |grep \"^vpc-$valid_tag_string\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ]; then inc_secure "AWS VPC \"${vpc}\" has a valid Name tag" else inc_insecure "AWS VPC \"${vpc}\" does not have a valid Name tag" fi fi fi fi done # Check VPN tunnel redundancy command="aws ec2 describe-vpn-connections --region \"${aws_region}\" --query \"VpnConnections[].VpnConnectionId\" --output text" command_message "${command}" tunnels=$( eval "${command}" ) for tunnel in ${tunnels}; do command="aws ec2 describe-vpn-connections --region \"${aws_region}\" --vpc-connection-ids \"${tunnel}\" --query \"VpnConnections[].VgwTelemetry[].Status\" |grep \"DOWN\"" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_insecure "AWS VPC \"${vpc}\" does not have VPN tunnel redundancy" else inc_secure "AWS VPC \"${vpc}\" has VPN tunnel redundancy" fi done } ================================================ FILE: modules/aws/network/audit_aws_vpcs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_vpcs # # Check VPCs # # Refer to Section(s) 4.2 Page(s) 133-4 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 4.3 Page(s) 135-7 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 4.4 Page(s) 138-40 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 4.5 Page(s) 141-2 CIS AWS Foundations Benchmark v1.1.0 # # Refer http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/SettingLogRetention.html # Refer to https://www.cloudconformity.com/conformity-rules/VPC/endpoint-exposed.html #. audit_aws_vpcs () { print_function "audit_aws_vpcs" check_message "VPCs" # Check for exposed VPC endpoints command="aws ec2 describe-vpc-endpoints --region \"${aws_region}\" --query 'VpcEndpoints[*].VpcEndpointId' --output text" command_message "${command}" endpoint_list=$( eval "${command}" ) for endpoint in ${endpoint_list}; do command="aws ec2 describe-vpc-endpoints --region \"${aws_region}\" --vpc-endpoint-ids \"$endpoint\" --query 'VpcEndpoints[].PolicyDocument' |grep Principal |grep -E \"\*|{\\\"AWS\\\":\\\"\*\\\"}\"" command_message "${command}" vpc=$( eval "${command}" ) if [ -n "${vpc}" ]; then inc_insecure "VPC \"${vpc}\" has en exposed enpoint" else inc_secure "VPC \"${vpc}\" does not have an exposed endpoint" fi done # Check for VPC peering command="aws ec2 describe-vpc-peering-connections --region \"${aws_region}\" --query VpcPeeringConnections --output text" command_message "${command}" vpc_peers=$( eval "${command}" ) if [ -z "${vpc_peers}" ]; then inc_secure "VPC peering is not being used" else command="aws ec2 describe-vpcs --query Vpcs[].VpcId --output text" command_message "${command}" vpcs=$( eval "${command}" ) for vpc in ${vpcs}; do command="aws ec2 describe-route-tables --region \"${aws_region}\" --filter \"Name=vpc-id,Values=${vpc}\" --query \"RouteTables[*].{RouteTableId:RouteTableId, VpcId:VpcId, Routes:Routes,AssociatedSubnets:Associations[*].SubnetId}\" | grep GatewayID | grep pcx-" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_secure "VPC \"${vpc}\" does not have a peer as it's gateway" else inc_insecure "VPC peering is being used review VPC: \"${vpc}\"" verbose_message "aws ec2 delete-route --region \"${aws_region}\" --route-table-id --destination-cidr-block " "fix" verbose_message "aws ec2 create-route --region \"${aws_region}\" --route-table-id --destination-cidr-block --vpc-peering-connection-id " "fix" fi done fi # Check for VPC flow logging command="aws ec2 describe-flow-logs --region \"${aws_region}\" --query FlowLogs[].FlowLogId --output text" command_message "${command}" logs=$( eval "${command}" ) if [ -n "${logs}" ]; then command="aws ec2 describe-vpcs --region \"${aws_region}\" --query Vpcs[].VpcId --output text" command_message "${command}" vpcs=$( eval "${command}" ) for vpc in ${vpcs}; do command="aws ec2 describe-flow-logs --region \"${aws_region}\" --query FlowLogs[].ResourceId --output text" command_message "${command}" vpc_check=$( eval "${command}" ) if [ "${vpc_check}" ]; then command="aws ec2 describe-flow-logs --region \"${aws_region}\" --filter \"Name=resource-id,Values=${vpc}\" | grep FlowLogStatus | grep ACTIVE" command_message "${command}" active_check=$( eval "${command}" ) if [ -n "${active_check}" ]; then inc_secure "VPC \"${vpc}\" has active flow logs" else inc_insecure "VPC \"${vpc}\" has flow logs but they are not active" fi else inc_insecure "VPC \"${vpc}\" does not have flow logs" fi done else inc_insecure "There are no VPC flow logs" fi } ================================================ FILE: modules/aws/security/audit_aws_access_keys.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_access_keys # # Check AWS Access Keys # # Refer to Section(s) 1.23 Page(s) 66-7 CIS AWS Foundations Benchmark v1.1.0 #. audit_aws_access_keys () { print_function "audit_aws_access_keys" check_message "Access Keys" command="aws iam generate-credential-report > /dev/null 2>&1" command_message "${command}" eval "${command}" command="aws iam get-credential-report --query 'Content' --output text | \"${base64_d}\" | cut -d, -f1,4,9,11,14,16 | sed '1 d' | grep -v '' | awk -F '\\\n' '{print \$1}'" command_message "${command}" eval "${command}" for entry in ${entries}; do aws_user=$( echo "${entry}" | cut -d, -f1 ) key1_use=$( echo "${entry}" | cut -d, -f3 ) key1_last=$( echo "${entry}" | cut -d, -f4 ) key2_use=$( echo "${entry}" | cut -d, -f5 ) key2_last=$( echo "${entry}" | cut -d, -f6 ) if [ "${key1_use}" = "true" ] && [ "${key1_last}" = "N/A" ]; then inc_insecure "Account \"${aws_user}\" has key access enabled but has not used their AWS API credentials consider removing keys" command="aws iam list-access-keys --user-name \"${aws_user}\" --query \"AccessKeyMetadata[].{AccessKeyId:AccessKeyId, Status:Status}\" --output text | grep Active | awk '{print \$1}'" command_message "${command}" key_ids=$( eval "${command}" ) for key_id in ${key_ids}; do lock_command="aws iam delete-access-key --access-key \"${key_id}\" --user-name \"${aws_user}\"" lock_message="Key \"${key_id}\" for user \"${aws_user}\" to disabled" run_lockdown "${lock_command}" "${lock_message}" "sudo" done else inc_secure "Account \"${aws_user}\" has key access enabled and has used their AWS API credentials" fi if [ "${key2_use}" = "true" ] && [ "${key2_last}" = "N/A" ]; then inc_insecure "Account \"${aws_user}\" has key access enabled but has not used their AWS API credentials consider removing keys" else inc_secure "Account \"${aws_user}\" has key access enabled and has used their AWS API credentials" fi done } ================================================ FILE: modules/aws/security/audit_aws_certs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_certs # # Check AWS Certificates # # Refer to https://www.cloudconformity.com/conformity-rules/IAM/expired-ssl-tls-certificate.html #. audit_aws_certs () { print_function "audit_aws_certs" check_message "Certificates" command="aws iam list-server-certificates --region \"${aws_region}\" --query \"ServerCertificateMetadataList[].ServerCertificateName\" --output text" command_message "${command}" certs=$( eval "${command}" ) command="date \"+%Y-%m-%dT%H:%M:%SS\"" command_message "${command}" cur_date=$( eval "${command}" ) if [ "${os_name}" = "Linux" ]; then command="date -d \"${cur_date}\" \"+%s\"" command_message "${command}" cur_secs=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%SS\" \"${cur_date}\" \"+%s\"" command_message "${command}" cur_secs=$( eval "${command}" ) fi for cert in ${certs}; do command="aws iam get-server-certificate --server-certificate-name \"${cert}\" --query \"ServerCertificate.ServerCertificateMetadata.Expiration\" --output text" command_message "${command}" exp_date=$( eval "${command}" ) if [ "${os_name}" = "Linux" ]; then command="date -d \"${exp_date}\" \"+%s\"" command_message "${command}" exp_secs=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%SZ\" \"${exp_date}\" \"+%s\"" command_message "${command}" exp_secs=$( eval "${command}" ) fi if [ "${exp_secs}" -lt "${cur_secs}" ]; then inc_insecure "Certificate \"${cert}\" has expired" else inc_secure "Certificate \"${cert}\" has not expired" fi done } ================================================ FILE: modules/aws/security/audit_aws_creds.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_creds # # Check AWS Credentials # # Refer to Section(s) 1.3 Page(s) 15-6 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.4 Page(s) 17-8 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.12 Page(s) 33-4 CIS AWS Foundations Benchmark v1.1.0 #. audit_aws_creds () { print_function "audit_aws_creds" check_message "Credentials" command="aws iam generate-credential-report > /dev/null 2>&1" command_message "${command}" eval "${command}" command="aws iam get-credential-report --query 'Content' --output text | \"${base64_d}\" | cut -d, -f1,4,5,6,9,10,11,14,15,16 | sed '1 d' | awk -F '\\\n' '{print \$1}'" command_message "${command}" entries=$( eval "${command}" ) for entry in ${entries}; do aws_user=$( echo "${entry}" | cut -d, -f1 ) aws_pass=$( echo "${entry}" | cut -d, -f2 ) aws_last=$( echo "${entry}" | cut -d, -f3 ) aws_rot=$( echo "${entry}" | cut -d, -f4 ) key1_use=$( echo "${entry}" | cut -d, -f5 ) key1_rot=$( echo "${entry}" | cut -d, -f6 ) key1_last=$( echo "${entry}" | cut -d, -f7 ) key2_use=$( echo "${entry}" | cut -d, -f8 ) key2_rot=$( echo "${entry}" | cut -d, -f9 ) key2_last=$( echo "${entry}" | cut -d, -f10 ) cur_sec=$( date "+%s" ) if [ "${aws_user}" = "" ]; then if [ "${key1_use}" = "true" ] || [ "${key2_use}" = "true" ]; then inc_insecure "Account \"${aws_user}\" is using access keys" else inc_secure "Account \"${aws_user}\" isn't using access keys" fi else if [ "${aws_pass}" = "false" ] && [ "${key1_use}" = "false" ] && [ "${key2_use}" = "false" ]; then inc_insecure "Account \"${aws_user}\" does not use any AWS credentials consider removing account" else if [ "${aws_pass}" = "true" ]; then a_test=$( echo "${aws_last}" |grep "[0-9]" ) if [ -n "$a_test" ]; then if [ "${os_name}" = "Linux" ]; then command="date -d \"${aws_last}\" \"+%s\"" command_message "${command}" aws_sec=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%S+00:00\" \"${aws_last}\" \"+%s\"" command_message "${command}" aws_sec=$( eval "${command}" ) fi aws_days=$( echo "(${cur_sec} - ${aws_sec})/84600" | bc ) if [ "$aws_days" -gt 90 ]; then inc_insecure "Account ${aws_user} has not used AWS Console credentials in over 90 days consider locking access" else inc_secure "Account ${aws_user} has used AWS Console credentials in the past 90 days" fi fi a_test=$( echo "${aws_rot}" |grep "[0-9]" ) if [ -n "$a_test" ]; then if [ "${os_name}" = "Linux" ]; then command="date -d \"${aws_last}\" \"+%s\"" command_message "${command}" rot_sec=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%S+00:00\" \"${aws_last}\" \"+%s\"" command_message "${command}" rot_sec=$( eval "${command}" ) fi rot_days=$( echo "(${rot_sec} - ${cur_sec})/84600" | bc ) if [ "${rot_days}" -gt 90 ]; then inc_insecure "Account \"${aws_user}\" will not rotate their AWS Console password in the next 90 days consider locking access" else inc_secure "Account \"${aws_user}\" will rotate their AWS Console password in the past 90 days" fi else inc_insecure "Account \"${aws_user}\" will not rotate their AWS Console password in the next 90 days consider locking access" fi fi if [ "${key1_use}" = "true" ]; then if [ "${os_name}" = "Linux" ]; then command="date -d \"${key1_last}\" \"+%s\"" command_message "${command}" key1_sec=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%S+00:00\" \"${key1_last}\" \"+%s\"" command_message "${command}" key1_sec=$( eval "${command}" ) fi key1_days=$( echo "(${cur_sec} - ${key1_sec})/84600" | bc ) if [ "${key1_days}" -gt 90 ]; then inc_insecure "Account \"${aws_user}\" has not used AWS API credentials in over 90 days consider removing keys" else inc_secure "Account \"${aws_user}\" has used AWS API credentials in the past 90 days" fi k_test=$( echo "${key1_rot}" |grep "[0-9]" ) if [ -n "${k_test}" ]; then if [ "${os_name}" = "Linux" ]; then command="date -d \"${key1_rot}\" \"+%s\"" command_message "${command}" rot_sec=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%S+00:00\" \"${key1_rot}\" \"+%s\"" command_message "${command}" rot_sec=$( eval "${command}" ) fi rot_days=$( echo "(${cur_sec} - ${rot_sec})/84600" | bc ) if [ "${rot_days}" -gt 90 ]; then inc_insecure "Account \"${aws_user}\" will not rotate their AWS API credentials in the next 90 days" else inc_secure "Account \"${aws_user}\" has rotated their AWS API credentials in the last 90 days" fi else inc_insecure "Account \"${aws_user}\" will not rotate their AWS API credentials in the next 90 days" fi fi if [ "${key2_use}" = "true" ]; then if [ "${os_name}" = "Linux" ]; then command="date -d \"${key2_last}\" \"+%s\"" command_message "${command}" key2_sec=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%S+00:00\" \"${key2_last}\" \"+%s\"" command_message "${command}" key2_sec=$( eval "${command}" ) fi key2_days=$( echo "(${cur_sec} - ${key2_sec})/84600" | bc ) if [ "${key2_days}" -gt 90 ]; then inc_insecure "Account \"${aws_user}\" has not used AWS SOA credentials in over 90 days consider removing keys" else inc_secure "Account \"${aws_user}\" has used AWS SOA credentials in the past 90 days" fi k_test=$( echo "${key2_rot}" |grep "[0-9]" ) if [ -n "${k_test}" ]; then if [ "${os_name}" = "Linux" ]; then command="date -d \"${key2_rot}\" \"+%s\"" command_message "${command}" rot_sec=$( eval "${command}" ) else command="date -j -f \"%Y-%m-%dT%H:%M:%S+00:00\" \"${key2_rot}\" \"+%s\"" command_message "${command}" rot_sec=$( eval "${command}" ) fi rot_days=$( echo "(${cur_sec} - ${rot_sec})/84600" | bc ) if [ "${rot_days}" -gt 90 ]; then inc_insecure "Account \"${aws_user}\" will not rotate their AWS SOA credentials in the next 90 days" else inc_secure "Account \"${aws_user}\" has rotated their AWS SOA credentials in the last 90 days" fi else inc_insecure "Account \"${aws_user}\" will not rotate their AWS SOA credentials in the next 90 days" fi fi fi fi done } ================================================ FILE: modules/aws/security/audit_aws_iam.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_iam # # Check AWS IAM # # Refer to Section(s) 1.1 Page(s) 10-1 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.18 Page(s) 46-57 CIS AWS Foundations Benchmark v1.1.0 # # Refer to http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html # Refer to https://www.cloudconformity.com/conformity-rules/IAM/unused-iam-group.html # Refer to https://www.cloudconformity.com/conformity-rules/IAM/unused-iam-user.html # Refer to https://www.cloudconformity.com/conformity-rules/IAM/iam-user-policies.html #. audit_aws_iam () { # Root account should only be used sparingly, admin functions and responsibilities should be delegated print_function "audit_aws_iam" check_message "IAM" command="aws iam generate-credential-report > /dev/null 2>&1" command_message "${command}" eval "${command}" command="date +%Y-%m" command_message "${command}" date_test=$( eval "${command}" ) command="aws iam get-credential-report --query 'Content' --output text | \"${base64_d}\" | cut -d, -f1,5,11,16 | grep -B1 '' | cut -f2 -d, | cut -f1,2 -d- | grep '[0-9]'" command_message "${command}" last_login=$( eval "${command}" ) if [ "${date_test}" = "${last_login}" ]; then inc_insecure "Root account appears to be being used regularly" else inc_secure "Root account does not appear to be being used frequently" fi # Check to see if there is an IAM master role command="aws iam get-role --role-name \"${aws_iam_master_role}\" 2> /dev/null" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "IAM Master role \"${aws_iam_master_role}\" ${exists}" else inc_insecure "IAM Master role \"${aws_iam_master_role}\" does not exist" verbose_message "cd aws" "fix" verbose_message "aws iam create-role --role-name ${aws_iam_master_role} --assume-role-policy-document file://account-creation-policy.json" "fix" verbose_message "aws iam put-role-policy --role-name ${aws_iam_master_role} --policy-name ${aws_iam_master_role} --policy-document file://iam-master-policy.json" "fix" fi # Check there is an IAM manager role command="aws iam get-role --role-name \"${aws_iam_manager_role}\" 2> /dev/null" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "IAM Manager role \"${aws_iam_manager_role}\" ${exists}" else inc_insecure "IAM Manager role \"${aws_iam_manager_role}\" does not exist" verbose_message "cd aws" "fix" verbose_message "aws iam create-role --role-name ${aws_iam_master_role} --assume-role-policy-document file://account-creation-policy.json" "fix" verbose_message "aws iam put-role-policy --role-name ${aws_iam_manager_role} --policy-name ${aws_iam_manager_role} --policy-document file://iam-manager-policy.json" "fix" fi # Check groups have members command="aws iam list-groups --query 'Groups[].GroupName' --output text" command_message "${command}" groups=$( eval "${command}" ) for group in ${groups}; do command="aws iam get-group --group-name \"${group}\" --query \"Users\" --output text" command_message "${command}" users=$( eval "${command}" ) if [ -n "${users}" ]; then inc_secure "IAM group \"${group}\" is not empty" else inc_insecure "IAM group \"${group}\" is empty" fi done command="aws iam list-users --query 'Users[].UserName' --output text" command_message "${command}" users=$( eval "${command}" ) for user in ${users}; do # Check for inactive users command="aws iam list-access-keys --user-name \"${user}\" --query \"AccessKeyMetadata\" --output text" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "IAM user \"${user}\" is active" else inc_insecure "IAM user \"${user}\" is not active" verbose_message "aws iam delete-user --user-name ${user}" "fix" fi # Check users do not have attached policies, they should be members of groups which have those policies command="aws iam list-attached-user-policies --user-name \"${user}\" --query \"AttachedPolicies[].PolicyArn\" --output text" command_message "${command}" policies=$( eval "${command}" ) if [ -n "${policies}" ]; then for policy in ${policies}; do inc_insecure "IAM user \"${user}\" has attached policy \"${policy}\"" verbose_message "aws iam detach-user-policy --user-name ${user} --policy-arn ${policy}" "fix" done else inc_secure "IAM user \"${user}\" does not have attached policies" fi done } ================================================ FILE: modules/aws/security/audit_aws_keys.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_keys # # Check AWS KMS Keyd # # Refer to Section(s) 2.8 Page(s) 85-6 CIS AWS Foundations Benchmark v1.1.0 # # Refer to https://www.cloudconformity.com/conformity-rules/IAM/unnecessary-ssh-public-keys.html # Refer to https://www.cloudconformity.com/conformity-rules/KMS/key-rotation-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/KMS/unused-customer-master-key.html #. audit_aws_keys () { print_function "audit_aws_keys" check_message "KMS Keys" command="aws kms list-keys --query Keys --output text" command_message "${command}" keys=$( eval "${command}" ) if [ "${keys}" ]; then for key in ${keys}; do # Check key is enabled command="aws kms get-key-rotation-status --key-id \"${key}\" --query 'KeyMetadata' | grep Enabled | grep true" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_insecure "Key \"${key}\" is not enabled" verbose_message "aws kms schedule-key-deletion --key-id ${key} --pending-window-in-days $aws_days_to_key_deletion" "fix" else inc_secure "Key \"${key}\" is enabled" fi # Check that key rotation is enabled command="aws kms get-key-rotation-status --key-id \"${key}\" |grep KeyRotationEnabled | grep true" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_insecure "Key \"${key}\" does not have key rotation enabled" verbose_message "aws cloudtrail update-trail --name --kms-id aws kms put-key-policy --key-id --policy " "fix" verbose_message "aws kms enable-key-rotation --key-id " "fix" else inc_secure "Key \"${key}\" has rotation enabled" fi done else inc_insecure "No Keys are being used" fi # Check for SSH keys command="aws iam list-users --query 'Users[].UserName' --output text" command_message "${command}" users=$( eval "${command}" ) for user in ${users}; do command="aws iam list-ssh-public-keys --region \"${aws_region}\" --user-name \"${user}\" | grep -c Active" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" -gt 1 ]; then inc_insecure "User \"${user}\" does has more than one active SSH key" else if [ "${check}" -eq 0 ]; then inc_secure "User \"${user}\" does not have any active SSH key" else inc_secure "User \"${user}\" does not have more than one active SSH key" fi fi done } ================================================ FILE: modules/aws/security/audit_aws_mfa.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_mfa # # Check AWS MFA # # Refer to Section(s) 1.2 Page(s) 12-4 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.13 Page(s) 35-6 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.14 Page(s) 37-8 CIS AWS Foundations Benchmark v1.1.0 # # Refer to http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html # Refer to http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html # Refer to http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_physical.html#enable-hw-mfa-for-root #. audit_aws_mfa () { print_function "audit_aws_mfa" check_message "MFA" command="aws iam get-credential-report --query 'Content' --output text | \"${base64_d}\" | cut -d, -f1,4,8 | sed '1 d' | awk -F '\\\n' '{print \$1}'" command_message "${command}" entries=$( eval "${command}" ) for entry in ${entries}; do user=$( echo "${entry}" | cut -d, -f1 ) pass=$( echo "${entry}" | cut -d, -f2 ) mfa=$( echo "${entry}" | cut -d, -f3 ) if [ "${user}" = "" ]; then if [ "${mfa}" = "false" ]; then inc_insecure "Account \"${user}\" does not have MFA enabled" else inc_secure "Account \"${user}\" has MFA enabled" fi else if [ "${pass}" != "false" ]; then if [ "${mfa}" = "false" ]; then inc_insecure "Account \"${user}\" does not have MFA enabled" else inc_secure "Account \"${user}\" has MFA enabled" fi else inc_secure "Account \"${user}\" does not log into console" fi fi done command="aws iam get-account-summary | grep \"AccountMFAEnabled\" | cut -f1 -d: | sed \"s/ //g\" | sed \"s/,//g\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" = "1" ]; then inc_secure "The root account has MFA enabled" command="iaws iam list-virtual-mfa-devices | grep \"SerialNumber\" | grep -c \"root_account\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" = "0" ]; then inc_secure "The root account does not have a virtual MFA" else inc_insecure "The root account does not have a hardware MFA" fi else inc_insecure "The root account does not have MFA enabled" inc_insecure "The root account does not a hardware MFA" fi } ================================================ FILE: modules/aws/security/audit_aws_password_policy.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_password_policy # # Check AWS Password Policy # # Refer to Section(s) 1.5 Page(s) 19-20 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.6 Page(s) 21-22 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.7 Page(s) 23-24 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.8 Page(s) 25-26 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.9 Page(s) 27-28 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.10 Page(s) 29-30 CIS AWS Foundations Benchmark v1.1.0 # Refer to Section(s) 1.11 Page(s) 31-32 CIS AWS Foundations Benchmark v1.1.0 #. audit_aws_password_policy () { print_function "audit_aws_password_policy" check_message "Password Policy" command="aws iam get-account-password-policy 2> /dev/null" command_message "${command}" policy=$( eval "${command}" ) command="echo \"${policy}\" | wc -l | sed \"s/ //g\"" command_message "${command}" length=$( eval "${command}" ) if [ "${length}" = "0" ]; then inc_insecure "No password policy ${exists}" fix_message "aws iam update-account-password-policy --require-uppercase-characters" fix_message "aws iam update-account-password-policy --require-lowercase-characters" fix_message "aws iam update-account-password-policy --require-symbols" fix_message "aws iam update-account-password-policy --require-numbers" fix_message "aws iam update-account-password-policy --minimum-password-length 14" fix_message "aws iam update-account-password-policy --password-reuse-prevention 24" fix_message "aws iam update-account-password-policy --max-password-age 90" else check_aws_password_policy "RequireUppercaseCharacters" "true" "--require-uppercase-characters" check_aws_password_policy "RequireLowercaseCharacters" "true" "--require-lowercase-characters" check_aws_password_policy "RequireSymbols" "true" "--require-symbols" check_aws_password_policy "RequireNumbers" "true" "--require-numbers" check_aws_password_policy "MinimumPasswordLength" "14" "--minimum-password-length 14" check_aws_password_policy "PasswordReusePrevention" "24" "--password-reuse-prevention 24" check_aws_password_policy "MaxPasswordAge" "90" "--max-password-age 90" fi } ================================================ FILE: modules/aws/security/audit_aws_sgs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_sgs # # Check AWS Security Groups # # Refer to https://www.cloudconformity.com/conformity-rules/EC2/security-group-ingress-any.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-ssh-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-rdp-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-cifs-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-dns-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-ftp-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-mongodb-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-netbios-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-rpc-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-icmp-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-smtp-access.html # Refer to https://www.cloudconformity.com/conformity-rules/EC2/unrestricted-telnet-access.html #. audit_aws_sgs () { print_function "audit_aws_sgs" check_message "Security Groups" command="aws ec2 describe-security-groups --region \"${aws_region}\" --query SecurityGroups[].GroupId --output text" command_message "${command}" sgs=$( eval "${command}" ) for sg in ${sgs}; do command="aws ec2 describe-security-groups --region \"${aws_region}\" --group-ids \"${sg}\" --filters ansible_value=group-name,Values='default' --query 'SecurityGroups[*].{IpPermissions:IpPermissions,GroupId:GroupId}' | grep \"0.0.0.0/0\"" command_message "${command}" in_check=$( eval "${command}" ) if [ -z "${in_check}" ]; then inc_secure "Security Group \"${sg}\" does not have a open inbound rule" else check_aws_open_port "${sg}" "-1" "icmp" "ICMP" "none" "none" check_aws_open_port "${sg}" "20,21" "tcp" "FTP" "none" "none" check_aws_open_port "${sg}" "22" "tcp" "SSH" "none" "none" check_aws_open_port "${sg}" "23" "tcp" "Telnet" "none" "none" check_aws_open_port "${sg}" "25" "tcp" "SMTP" "none" "none" check_aws_open_port "${sg}" "53" "tcp" "DNS" "none" "none" check_aws_open_port "${sg}" "80" "tcp" "HTTP" "none" "none" check_aws_open_port "${sg}" "135" "tcp" "RPC" "none" "none" check_aws_open_port "${sg}" "137,138,139" "tcp" "SMB" "none" "none" check_aws_open_port "${sg}" "443" "tcp" "HTTPS" "none" "none" check_aws_open_port "${sg}" "445" "tcp" "CIFS" "none" "none" check_aws_open_port "${sg}" "1433" "tcp" "MSSQL" "none" "none" check_aws_open_port "${sg}" "1521" "tcp" "Oracle" "none" "none" check_aws_open_port "${sg}" "3306" "tcp" "MySQL" "none" "none" check_aws_open_port "${sg}" "3389" "tcp" "RDP" "none" "none" check_aws_open_port "${sg}" "5432" "tcp" "PostgreSQL" "none" "none" check_aws_open_port "${sg}" "27017" "tcp" "MongoDB" "none" "none" fi command="aws ec2 describe-security-groups --region \"${aws_region}\" --group-ids \"${sg}\" --filters ansible_value=group-name,Values='default' --query 'SecurityGroups[*].{IpPermissionsEgress:IpPermissionsEgress,GroupId:GroupId}' | grep \"0.0.0.0/0\"" command_message "${command}" out_check=$( eval "${command}" ) if [ -z "${out_check}" ]; then inc_secure "Security Group \"${sg}\" does not have a open outbound rule" else inc_insecure "Security Group \"${sg}\" has an open outbound rule" verbose_message "aws ec2 revoke-security-group-egress --region \"${aws_region}\" --group-name \"${sg}\" --protocol tcp --cidr 0.0.0.0/0" "fix" fi done } ================================================ FILE: modules/aws/storage/audit_aws_cdn.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_cdn # # Check AWS Cloudfront # # Refer to https://www.cloudconformity.com/conformity-rules/CloudFront/cloudfront-integrated-with-waf.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudFront/cloudfront-logging-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudFront/cloudfront-insecure-origin-ssl-protocols.html # Refer to https://www.cloudconformity.com/conformity-rules/CloudFront/cloudfront-traffic-to-origin-unencrypted.html #. audit_aws_cdn () { print_function "audit_aws_cdn" check_message "Cloudfront" aws configure set preview.cloudfront true command="aws cloudfront list-distributions --query 'DistributionList.Items[].Id' --output text | grep -v null" command_message "${command}" cdns=$( eval "${command}" ) for cdn in ${cdns}; do # Check Cloudfront is using WAF command="aws cloudfront get-distribution --id \"${cdn}\" --query 'Distribution.DistributionConfig.WebACLId' --output text" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ]; then inc_secure "Cloudfront CDN \"${cdn}\" is WAF integration enabled" else inc_insecure "Cloudfront CDN \"${cdn}\" is not WAF integration enabled" fi # Check logging is enabled command="aws cloudfront get-distribution --id \"${cdn}\" --query 'Distribution.DistributionConfig.Logging.Enabled' | grep true" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" ]; then inc_secure "Cloudfront CDN \"${cdn}\" has logging enabled" else inc_insecure "Cloudfront CDN \"${cdn}\" does not have logging enabled" fi # check SSL protocol versions being used against deprecated ones command="aws cloudfront get-distribution --id \"${cdn}\" --query 'Distribution.DistributionConfig.Origins.Items[].CustomOriginConfig.OriginSslProtocols.Items' | grep -E \"SSLv3|SSLv2\"" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_secure "Cloudfront CDN \"${cdn}\" is not using a deprecated version of SSL" else inc_insecure "Cloudfront CDN \"${cdn}\" is using a deprecated verions of SSL" fi # check if HTTP only being used command="aws cloudfront get-distribution --id \"${cdn}\" --query 'Distribution.DistributionConfig.Origins.Items[].CustomOriginConfig.OriginProtocolPolicy' | grep -E \"http-only\"" command_message "${command}" check=$( eval "${command}" ) if [ ! "${check}" ]; then inc_secure "Cloudfront CDN \"${cdn}\" is not using HTTP only" else inc_insecure "Cloudfront CDN \"${cdn}\" is using HTTP only" fi done } ================================================ FILE: modules/aws/storage/audit_aws_s3.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aws_s3 # # Check AWS S3 # # Refer to https://www.cloudconformity.com/conformity-rules/S3/s3-bucket-authenticated-users-full-control-access.html # Refer to https://www.cloudconformity.com/conformity-rules/S3/s3-bucket-logging-enabled.html # Refer to https://www.cloudconformity.com/conformity-rules/S3/s3-bucket-public-full-control-access.html #. audit_aws_s3 () { print_function "audit_aws_s3" check_message "S3" command="aws s3api list-buckets --region \"${aws_region}\" --query 'Buckets[*].Name' --output text" command_message "${command}" buckets=$( eval "${command}" ) for bucket in ${buckets}; do for user in http://acs.amazonaws.com/groups/global/AllUsers http://acs.amazonaws.com/groups/global/AuthenticatedUsers; do command="aws s3api get-bucket-acl --region \"${aws_region}\" --bucket \"${bucket}\" | grep URI | grep \"${user}\"" command_message "${command}" grants=$( eval "${command}" ) if [ -n "${grants}" ]; then inc_insecure "Bucket \"${bucket}\" grants access to Principal \"${user}\"" else inc_secure "Bucket \"${bucket}\" does not grant access to Principal \"${user}\"" fi done command="aws s3api get-bucket-logging --region \"${aws_region}\" --bucket \"${bucket}\"" command_message "${command}" check=$( eval "${command}" ) if [ -z "${check}" ]; then inc_insecure "Bucket ${bucket} does not have access logging enabled" verbose_message "aws s3api put-bucket-acl --region \"${aws_region}\" --bucket \"${bucket}\" --grant-write URI=http://acs.amazonaws.com/groups/s3/LogDelivery --grant-read-acp URI=http://acs.amazonaws.com/groups/s3/LogDelivery" "fix" verbose_message "cd aws ; aws s3api put-bucket-logging --region \"${aws_region}\" --bucket \"${bucket}\" --bucket-logging-status file://server-access-logging.json" else inc_secure "Bucket \"${bucket}\" has access logging enabled" fi command="aws s3api get-bucket-versioning --bucket \"${bucket}\" | grep Enabled" command_message "${command}" check=$( eval "${command}" ) if [ -n "${check}" ]; then inc_secure "Bucket \"${bucket}\" has versioning enabled" else inc_insecure "Bucket \"${bucket}\" does not have versioning enabled" fi done } ================================================ FILE: modules/azure/compute/batch/audit_azure_batch.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_batch # # Check Azure Batch # # 15.1 Ensure Batch account is set to use customer-managed keys to encrypt data - TBD # 15.2 Ensure Batch pools disk encryption is set enabled - TBD # 15.3 Ensure local authentication methods for accounts are disabled - TBD # 15.4 Ensure Private endpoints are considered for Batch accounts - TBD # 15.5 Ensure public network access is disabled for Batch accounts - TBD # 15.6 Ensure private DNS zones for private endpoints that connect to Batch accounts are configured - TBD # 15.7 Ensure Diagnostics settings logs for Batch accounts are enabled - TBD # # Refer to Section(s) 15- Page(s) 277- CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_batch () { print_function "audit_azure_batch" check_message "Azure Batch" command="az batch account list --query \"[].name\" --output tsv" command_message "${command}" batch_list=$( eval "${command}" 2> /dev/null ) if [ -z "${batch_list}" ]; then info_message "No Batch accounts found" fi for batch_name in ${batch_list}; do command="az batch account show --name \"${batch_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 15.1 Ensure Batch account is set to use customer-managed keys to encrypt data - TBD check_azure_batch_value "Customer Managed Keys" "${batch_name}" "${res_group}" "keyVaultReference" "ne" "" "--encryption-key-identifier" "https://.vault.azure.net/keys//" # 15.3 Ensure local authentication methods for accounts are disabled - TBD check_azure_batch_value "Local Authentication Methods" "${batch_name}" "${res_group}" "allowedAuthenticationModes" "eq" "AAD" "" "" # 15.5 Ensure public network access is disabled for Batch accounts - TBD check_azure_batch_value "Public Network Access" "${batch_name}" "${res_group}" "publicNetworkAccess" "eq" "Disabled" "" "" # 15.2 Ensure Batch pools disk encryption is set enabled - TBD command="az batch pool list --account-name \"${batch_name}\" --query \"[].id\" --output tsv" command_message "${command}" pool_ids=$( eval "${command}" ) for pool_id in ${pool_ids}; do for disk_name in OsDisk TemporaryDisk; do check_azure_batch_pool_value "Batch pools disk encryption" "${pool_id}" "deploymentConfiguration.virtualMachineConfiguration.diskEncryption.Configuration.encryption.targets" "has" "${disk_name}" done done # 15.4 Ensure Private endpoints are considered for Batch accounts - TBD check_azure_network_private_endpoint_value "${res_group}" "[?privateLinkServiceConnections[?contains(properties.privateLinkServiceId, 'Microsoft.Batch/batchAccounts/${batch_name}')]]" "ne" "" done } ================================================ FILE: modules/azure/compute/container/audit_azure_container_instances.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_container_instances # # Check Azure Container Instances # # 3.1 Ensure Private Virtual Networks are used for Container Instances - TBD # 3.2 Ensure a Managed Identity is used for interactions with other Azure services - TBD # 3.3 Ensure the principle of least privilege is used when assigning roles to a Managed Identity - TBD # # Refer to Section(s) 3.1- Page(s) 255- CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_container_instances () { print_function "audit_azure_container_instances" check_message "Azure Container Instances" command="az container list --query \"[].name\" --output tsv" command_message "${command}" c_list=$( eval "${command}" 2> /dev/null ) if [ -z "${c_list}" ]; then info_message "No Container Instances found" fi for c_name in ${c_list}; do command="az container show --name \"${c_name}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_container_instance_value "Private Virtual Networks" "${c_name}" "${res_group}" "ipAddress.type" "eq" "Private" check_azure_container_instance_value "Managed Identity" "${c_name}" "${res_group}" "identity.type" "eq" "${azure_managed_identity}" done } ================================================ FILE: modules/azure/compute/cycle/audit_azure_cycle_cloud.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_cycle_cloud # # Check Azure CycleCloud # # Refer to Section(s) 2- Page(s) 22- CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_cycle_cloud () { print_function "audit_azure_cycle_cloud" check_message "Azure CycleCloud" } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_basic_authentication_publishing_credentials.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_basic_authentication_publishing_credentials # # 2.3.3 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # # Refer to Section(s) 2.3.3 Page(s) 149-51 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_basic_authentication_publishing_credentials () { print_function "audit_azure_function_app_basic_authentication_publishing_credentials" check_message "Azure Function Apps Basic Authentication Publishing Credentials" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Basic Authentication Publishing Credentials" "${app_id}" "${res_group}" "basicPublishingCredentialsPolicies" "ftp" "Microsoft.Web" "properties.allow" "eq" "false" "" "" check_azure_function_app_value "Basic Authentication Publishing Credentials" "${app_id}" "${res_group}" "basicPublishingCredentialsPolicies" "scm" "Microsoft.Web" "properties.allow" "eq" "false" "" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_client_certificates.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_client_certificates # # 2.3.10 Ensure incoming client certificates are enabled and required (if in use) - TBD # # Refer to Section(s) 2.3.10 Page(s) 169-71 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_client_certificates () { print_function "audit_azure_function_app_client_certificates" check_message "Azure Function Apps Client Certificates" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Client Certificates" "${app_id}" "${res_group}" "config" "web" "Microsoft.Web/sites" "clientCertEnabled" "eq" "true" "clientCertEnabled" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_cross_origin_resource_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_cross_origin_resource_sharing # # 2.3.17 Ensure cross-origin resource sharing does not allow all origins - TBD # # Refer to Section(s) 2.3.17 Page(s) 143-5 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_cross_origin_resource_sharing () { print_function "audit_azure_function_app_cross_origin_resource_sharing" check_message "Azure Function Apps Cross-Origin Resource Sharing" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Cross-Origin Resource Sharing" "${app_id}" "${res_group}" "config" "web" "cors" "siteConfig.cors.allowedOrigins" "ne" "*" "properties.cors.allowedOrigins" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_ftp_states.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_ftp_states # # 2.3.4 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD # # Refer to Section(s) 2.3.4 Page(s) 152-4 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_java_versions () { print_function "audit_azure_function_app_java_versions" check_message "Azure Function Apps Java Versions" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "FTP State" "${app_id}" "${res_group}" "config" "ftp" "" "ftpState" "eq" "${azure_ftp_state}" "--ftp-state" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_http_values.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_http_values # # 2.3.5 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.3.6 Ensure 'HTTPS Only' is set to 'On' - TBD # # Refer to Section(s) 2.3.5-6 Page(s) 155-60 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_http_values () { print_function "audit_azure_function_app_http_values" check_message "Azure Function Apps HTTP Values" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "HTTP Version" "${app_id}" "${res_group}" "config" "web" "" "http20Enabled" "eq" "true" "--http20-enabled" "" check_azure_function_app_value "HTTPS Only" "${app_id}" "${res_group}" "config" "web" "" "httpsOnly" "eq" "true" "httpsOnly" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_java_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_java_versions # # 2.3.1 Ensure 'Java version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.3.1 Page(s) 143-5 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_java_versions () { print_function "audit_azure_function_app_java_versions" check_message "Azure Function Apps Java Versions" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Java Version" "${app_id}" "${res_group}" "config" "web" "" "javaVersion" "eq" "${azure_java_version}" "--java-version" "" check_azure_function_app_value "Java Container Version" "${app_id}" "${res_group}" "config" "web" "" "javaContainerVersion" "eq" "${azure_java_version}" "--java-container-version" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_managed_identities.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_managed_identities # # 2.3.12 Ensure managed identities are configured - TBD # # Refer to Section(s) 2.3.12 Page(s) 175-7 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_managed_identities () { print_function "audit_azure_function_app_managed_identities" check_message "Azure Function Apps Managed Identities" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Managed Identities" "${app_id}" "${res_group}" "config" "web" "identity" "type" "eq" "${azure_managed_identity}" "" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_public_network_access.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_public_network_access # # 2.3.13 Ensure public network access is disabled - TBD # # Refer to Section(s) 2.3.13 Page(s) 178-80 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_public_network_access () { print_function "audit_azure_function_app_public_network_access" check_message "Azure Function Apps Public Network Access" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Public Network Access" "${app_id}" "${res_group}" "config" "web" "Microsoft.Web/sites" "publicNetworkAccess" "eq" "Disabled" "properties.publicNetworkAccess" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_python_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_apps # # 2.3.2 Ensure 'Python version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.3.2 Page(s) 146-8 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_apps () { print_function "audit_azure_functions_apps" check_message "Azure Function Apps" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Python Version" "${app_id}" "${res_group}" "config" "web" "" "pythonVersion" "eq" "${azure_python_version}" "--python-version" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_remote_debugging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_remote_debugging # # 2.3.9 Ensure 'Remote debugging' is set to 'Off' - TBD # # Refer to Section(s) 2.3.9 Page(s) 167-8 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_remote_debugging () { print_function "audit_azure_function_app_remote_debugging" check_message "Azure Function Apps Remote Debugging" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Remote Debugging" "${app_id}" "${res_group}" "config" "web" "" "remoteDebuggingEnabled" "eq" "false" "--remote-debugging-enabled" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_service_authentication.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_service_authentication # # 2.3.11 Ensure 'App Service authentication' is set to 'Enabled' - TBD # # Refer to Section(s) 2.3.11 Page(s) 172-4 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_service_authentication () { print_function "audit_azure_function_app_service_authentication" check_message "Azure Function Apps Service Authentication" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "App Service Authentication" "${app_id}" "${res_group}" "auth" "web" "Microsoft.Web/sites" "authSettings.enabled" "eq" "true" "properties.authSettings.enabled" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_tls_values.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_tls_values # # 2.3.7 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.3.8 Ensure end-to-end TLS encryption is enabled - TBD # # Refer to Section(s) 2.3.7-8 Page(s) 155-156 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_tls_values () { print_function "audit_azure_function_app_tls_values" check_message "Azure Function Apps TLS Values" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Minimum Inbound TLS Version" "${app_id}" "${res_group}" "config" "web" "" "minTlsVersion" "eq" "1.2" "--min-tls-version" "" check_azure_function_app_value "End-to-End TLS Encryption" "${app_id}" "${res_group}" "config" "web" "Microsoft.Web/sites" "endToEndEncryptionEnabled" "eq" "true" "properties.endToEndEncryptionEnabled" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_app_virtual_network_integration.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_app_virtual_network_integration # # 2.3.14 Ensure app is integrated with a virtual network - TBD # 2.3.15 Ensure configuration is routed through the virtual network integration - TBD # 2.3.16 Ensure all traffic is routed through the virtual network - TBD # # Refer to Section(s) 2.3.14, 2.3.15, 2.3.16 Page(s) 181- CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_app_virtual_network_integration () { print_function "audit_azure_function_app_virtual_network_integration" check_message "Azure Function Apps Virtual Network Integration" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_function_app_value "Virtual Network Integration" "${app_id}" "${res_group}" "config" "web" "" "virtualNetworkSubnetId" "ne" "" "" "" check_azure_function_app_value "VNet Image Pull" "${app_id}" "${res_group}" "config" "web" "Microsoft.Web/sites" "vnetImagePullEnabled" "eq" "true" "properties.vnetRouteAllEnabled" "" check_azure_function_app_value "VNet Content Share" "${app_id}" "${res_group}" "config" "web" "Microsoft.Web/sites" "vnetContentShareEnabled" "eq" "true" "properties.vnetContentShareEnabled" "" check_azure_function_app_value "VNet Route All" "${app_id}" "${res_group}" "config" "web" "Microsoft.Web/sites" "vnetRouteAllEnabled" "eq" "true" "properties.vnetRouteAllEnabled" "" done } ================================================ FILE: modules/azure/compute/function/apps/audit_azure_function_apps.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_apps # # Function Apps # 2.3.1 Ensure 'Java version' is currently supported (if in use) - TBD # 2.3.2 Ensure 'Python version' is currently supported (if in use) - TBD # 2.3.3 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # 2.3.5 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.3.6 Ensure 'HTTPS Only' is set to 'On' - TBD # 2.3.7 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.3.8 Ensure end-to-end TLS encryption is enabled - TBD # 2.3.9 Ensure 'Remote debugging' is set to 'Off' - TBD # 2.3.10 Ensure incoming client certificates are enabled and required (if in use) - TBD # 2.3.11 Ensure 'App Service authentication' is set to 'Enabled' - TBD # 2.3.12 Ensure managed identities are configured - TBD # 2.3.13 Ensure public network access is disabled - TBD # 2.3.14 Ensure function app is integrated with a virtual network - TBD # 2.3.15 Ensure configuration is routed through the virtual network integration - TBD # 2.3.16 Ensure all traffic is routed through the virtual network - TBD # 2.3.17 Ensure cross-origin resource sharing does not allow all origins - TBD # # Refer to Section(s) 2.3.1-17 Page(s) 142- CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_apps () { print_function "audit_azure_functions_apps" check_message "Azure Function Apps" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function Apps found" return fi # 2.3.1 Ensure 'Java version' is currently supported (if in use) - TBD audit_azure_function_app_java_versions # 2.3.2 Ensure 'Python version' is currently supported (if in use) - TBD audit_azure_function_app_python_versions # 2.3.3 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD audit_azure_function_app_basic_authentication_publishing_credentials # 2.3.4 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD audit_azure_function_app_ftp_states # 2.3.5 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.3.6 Ensure 'HTTPS Only' is set to 'On' - TBD audit_azure_function_app_http_values # 2.3.7 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.3.8 Ensure end-to-end TLS encryption is enabled - TBD audit_azure_function_app_tls_values # 2.3.9 Ensure 'Remote debugging' is set to 'Off' - TBD audit_azure_function_app_remote_debugging # 2.3.10 Ensure incoming client certificates are enabled and required (if in use) - TBD audit_azure_function_app_client_certificates # 2.3.11 Ensure 'App Service authentication' is set to 'Enabled' - TBD audit_azure_function_app_service_authentication # 2.3.12 Ensure managed identities are configured - TBD audit_azure_function_app_managed_identities # 2.3.13 Ensure public network access is disabled - TBD audit_azure_function_app_public_network_access # 2.3.14 Ensure app is integrated with a virtual network - TBD # 2.3.15 Ensure configuration is routed through the virtual network integration - TBD # 2.3.16 Ensure all traffic is routed through the virtual network - TBD audit_azure_function_app_virtual_network_integration # 2.3.17 Ensure cross-origin resource sharing does not allow all origins - TBD audit_azure_function_app_cross_origin_resource_sharing } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots # # Functions Deployment Slots # 2.4.1 Ensure 'Java version' is currently supported (if in use) - TBD # 2.4.2 Ensure 'Python version' is currently supported (if in use) - TBD # 2.4.3 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # 2.4.4 Ensure 'FTP state' is set to 'FTPS only' or 'Disabled' - TBD # 2.4.5 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.4.6 Ensure 'HTTPS Only' is set to 'On' - TBD # 2.4.7 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.4.8 Ensure end-to-end TLS encryption is enabled - TBD # 2.4.9 Ensure 'Remote debugging' is set to 'Off' - TBD # 2.4.10 Ensure incoming client certificates are enabled and required (if in use) - TBD # 2.4.11 Ensure managed identities are configured - TBD # 2.4.12 Ensure public network access is disabled - TBD # 2.4.13 Ensure deployment slot is integrated with a virtual network - TBD # 2.4.14 Ensure configuration is routed through the virtual network integration - TBD # 2.4.15 Ensure all traffic is routed through the virtual network - TBD # 2.4.16 Ensure cross-origin resource sharing does not allow all origins - TBD # # Refer to Section(s) 2.4.1-16 Page(s) 192-237 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots () { print_function "audit_azure_function_deployment_slots" check_message "Azure Function App Deployment Slots" command="az functionapp list --query \"[].name\" --output tsv" command_message "${command}" app_names=$( eval "${command}" 2> /dev/null ) if [ -z "${app_names}" ]; then info_message "No Function App Apps found" return fi for app_name in ${app_names}; do command="az functionapp show --name \"${app_name}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_name}\" --resource-group \"${res_group}\" --query \"[].name\" --output tsv" command_message "${command}" slot_names=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_names}" ]; then info_message "No Function App Deployment Slots found" return fi # 2.4.1 Ensure 'Java version' is currently supported (if in use) - TBD audit_azure_function_deployment_slots_java_versions # 2.4.2 Ensure 'Python version' is currently supported (if in use) - TBD audit_azure_function_deployment_slots_python_versions # 2.4.3 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD audit_azure_function_deployment_slots_basic_authentication_publishing_credentials # 2.4.4 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD audit_azure_function_deployment_slots_ftp_states # 2.4.5 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.4.6 Ensure 'HTTPS Only' is set to 'On' - TBD audit_azure_function_deployment_slots_http_values # 2.4.7 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.4.8 Ensure end-to-end TLS encryption is enabled - TBD audit_azure_function_deployment_slots_tls_values # 2.4.9 Ensure 'Remote debugging' is set to 'Off' - TBD audit_azure_function_deployment_slots_remote_debugging # 2.4.10 Ensure incoming client certificates are enabled and required (if in use) - TBD audit_azure_function_deployment_slots_client_certificates # 2.4.11 Ensure managed identities are configured - TBD audit_azure_function_deployment_slots_managed_identities # 2.4.12 Ensure public network access is disabled - TBD audit_azure_function_deployment_slots_public_network_access # 2.4.13 Ensure app is integrated with a virtual network - TBD # 2.4.14 Ensure configuration is routed through the virtual network integration - TBD audit_azure_function_deployment_slots_virtual_network_integration # 2.4.15 Ensure cross-origin resource sharing does not allow all origins - TBD audit_azure_function_deployment_slots_cross_origin_resource_sharing # 2.4.16 Ensure private endpoints are used to access App Service apps - TBD audit_azure_app_service_deployment_slots_private_endpoints done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_basic_authentication_publishing_credentials.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_basic_authentication_publishing_credentials # # 2.4.3 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # # Refer to Section(s) 2.4.3 Page(s) 199-201 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_basic_authentication_publishing_credentials () { print_function "audit_azure_function_deployment_slots_basic_authentication_publishing_credentials" check_message "Azure Function App Deployment Slots Basic Authentication Publishing Credentials" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Basic Authentication Publishing Credentials" "${slot_id}" "${app_name}" "${res_group}" "basicPublishingCredentialsPolicies" "ftp" "Microsoft.Web/sites" "properties.allow" "eq" "false" "" "" check_azure_function_deployment_slot_value "Basic Authentication Publishing Credentials" "${slot_id}" "${app_name}" "${res_group}" "basicPublishingCredentialsPolicies" "scm" "Microsoft.Web/sites" "properties.allow" "eq" "false" "" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_client_certificates.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_client_certificates # # 2.4.10 Ensure incoming client certificates are enabled and required (if in use) - TBD # # Refer to Section(s) 2.4.10 Page(s) 219-21 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_client_certificates () { print_function "audit_azure_function_deployment_slots_client_certificates" check_message "Azure Function App Deployment Slots Client Certificates" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Client Certificates" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "clientCertEnabled" "eq" "true" "clientCertEnabled" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_cross_origin_resource_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_cross_origin_resource_sharing # # 2.4.15 Ensure cross-origin resource sharing does not allow all origins - TBD # # Refer to Section(s) 2.4.15 Page(s) 232-4 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_cross_origin_resource_sharing () { print_function "audit_azure_function_deployment_slots_cross_origin_resource_sharing" check_message "Azure Function App Deployment Slots Cross-Origin Resource Sharing" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Cross-Origin Resource Sharing" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "cors" "siteConfig.cors.allowedOrigins" "ne" "*" "properties.cors.allowedOrigins" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_ftp_states.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_ftp_states # # 2.4.4 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD # # Refer to Section(s) 2.4.4 Page(s) 203-4 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_ftp_states () { print_function "audit_azure_function_deployment_slots_ftp_states" check_message "Azure Function App Deployment Slots FTP States" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "FTP State" "${slot_id}" "${app_name}" "${res_group}" "config" "ftp" "Microsoft.Web/sites" "ftpState" "eq" "${azure_ftp_state}" "--ftp-state" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_http_values.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_http_values # # 2.4.5 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.4.6 Ensure 'HTTPS Only' is set to 'On' - TBD # # Refer to Section(s) 2.4.5-6 Page(s) 205-10 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_http_values () { print_function "audit_azure_function_deployment_slots_http_values" check_message "Azure Function App Deployment Slots HTTP Values" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "HTTP Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "http20Enabled" "eq" "true" "--http20-enabled" "" check_azure_function_deployment_slot_value "HTTPS Only" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "httpsOnly" "eq" "true" "httpsOnly" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_java_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_java_versions # # 2.4.1 Ensure 'Java version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.4.1 Page(s) 193-5 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_java_versions () { print_function "audit_azure_function_deployment_slots_java_versions" check_message "Azure Function App Deployment Slots Java Versions" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Java Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "javaVersion" "eq" "${azure_java_version}" "--java-version" "" check_azure_function_deployment_slot_value "Java Container Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "javaContainerVersion" "eq" "${azure_java_version}" "--java-container-version" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_managed_identities.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_managed_identities # # 2.4.11 Ensure managed identities are configured - TBD # # Refer to Section(s) 2.4.11 Page(s) 222-4 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_managed_identities () { print_function "audit_azure_function_deployment_slots_managed_identities" check_message "Azure Function App Deployment Slots Managed Identities" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Managed Identities" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "identity" "type" "eq" "${azure_managed_identity}" "" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_private_endpoints.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_private_endpoints # # 2.4.16 Ensure private endpoints are used to access App Service apps - TBD # # Refer to Section(s) 2.4.16 Page(s) 235-7 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_private_endpoints () { print_function "audit_azure_function_deployment_slots_private_endpoints" check_message "Azure Function App Deployment Slots Private Endpoints" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_network_private_endpoint_value "${app_id}" "[*].privateLinkServiceConnections[*].[privateLinkServiceId,privateLinkServiceConnectionState.status]" "eq" "Approved" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_public_network_access.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_public_network_access # # 2.4.12 Ensure public network access is disabled - TBD # # Refer to Section(s) 2.4.12 Page(s) 225-7 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_public_network_access () { print_function "audit_azure_function_deployment_slots_public_network_access" check_message "Azure Function App Deployment Slots Public Network Access" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Public Network Access" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "publicNetworkAccess" "eq" "Disabled" "properties.publicNetworkAccess" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_python_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_python_versions # # 2.4.2 Ensure 'Python version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.4.2 Page(s) 196-8 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_python_versions () { print_function "audit_azure_function_deployment_slots_python_versions" check_message "Azure Function App Deployment Slots Python Versions" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Python Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "pythonVersion" "eq" "${azure_python_version}" "--python-version" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_remote_debugging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_remote_debugging # # 2.4.9 Ensure 'Remote debugging' is set to 'Off' - TBD # # Refer to Section(s) 2.4.9 Page(s) 216-8 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_remote_debugging () { print_function "audit_azure_function_deployment_slots_remote_debugging" check_message "Azure Function App Deployment Slots Remote Debugging" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Remote Debugging" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "remoteDebuggingEnabled" "eq" "false" "--remote-debugging-enabled" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_tls_values.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_tls_values # # 2.4.7 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.4.8 Ensure end-to-end TLS encryption is enabled - TBD # # Refer to Section(s) 2.4.7-8 Page(s) 211-5 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_tls_values () { print_function "audit_azure_function_deployment_slots_tls_values" check_message "Azure Function App Deployment Slots TLS Values" command="az functionapp list --query \"[].name\" --output tsv" command_message "${command}" app_names=$( eval "${command}" 2> /dev/null ) if [ -z "${app_names}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Minimum Inbound TLS Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "minTlsVersion" "eq" "1.2" "--min-tls-version" "" check_azure_function_deployment_slot_value "End-to-End TLS Encryption" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "endToEndEncryptionEnabled" "eq" "true" "properties.endToEndEncryptionEnabled" "" done done } ================================================ FILE: modules/azure/compute/function/slots/audit_azure_function_deployment_slots_virtual_network_integration.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_function_deployment_slots_virtual_network_integration # # 2.4.13 Ensure app is integrated with a virtual network - TBD # 2.4.14 Ensure configuration is routed through the virtual network integration - TBD # # Refer to Section(s) 2.4.13-4 Page(s) 228-31 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_function_deployment_slots_virtual_network_integration () { print_function "audit_azure_function_deployment_slots_virtual_network_integration" check_message "Azure Function App Deployment Slots Virtual Network Integration" command="az functionapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No Function App Apps found" return fi for app_id in ${app_ids}; do command="az functionapp show --name \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az functionapp show --name \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az functionapp deployment slot list --name \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No Function App Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_function_deployment_slot_value "Virtual Network Integration" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "virtualNetworkSubnetId" "ne" "" "" "" check_azure_function_deployment_slot_value "VNet Image Pull" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "vnetRouteAllEnabled" "eq" "true" "properties.vnetRouteAllEnabled" "" check_azure_function_deployment_slot_value "VNet Content Share" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "vnetContentShareEnabled" "eq" "true" "properties.vnetContentShareEnabled" "" done done } ================================================ FILE: modules/azure/compute/main/audit_azure_compute_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_compute_services # # Check Azure Compute Services # # Refer to Section(s) 3 Page(s) 63-8 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to CIS Microsoft Azure Compute Services Benchmark # # 2.1 App Service Apps # 2.1.1 Ensure 'Java version' is currently supported (if in use) - TBD # 2.1.2 Ensure 'Python version' is currently supported (if in use) - TBD # 2.1.3 Ensure 'PHP version' is currently supported (if in use) - TBD # 2.1.4 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # 2.1.5 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD # 2.1.6 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.1.7 Ensure 'HTTPS Only' is set to 'On' - TBD # 2.1.8 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.1.9 Ensure end-to-end TLS encryption is enabled - TBD # 2.1.10 Ensure 'Remote debugging' is set to 'Off' - TBD # 2.1.11 Ensure incoming client certificates are enabled and required (if in use) - TBD # 2.1.12 Ensure 'App Service authentication' is set to 'Enabled' - TBD # 2.1.13 Ensure managed identities are configured - TBD # 2.1.14 Ensure public network access is disabled - TBD # 2.1.15 Ensure App Service plan SKU supports private endpoints - TBD # 2.1.16 Ensure private endpoints are used to access App Service apps - TBD # 2.1.17 Ensure private endpoints used to access App Service apps use private DNS zones - TBD # 2.1.18 Ensure app is integrated with a virtual network - TBD # 2.1.19 Ensure configuration is routed through the virtual network integration - TBD # 2.1.20 Ensure all traffic is routed through the virtual network - TBD # 2.1.21 Ensure cross-origin resource sharing does not allow all origins - TBD # # 2.2 App Service Deployment Slots # 2.2.1 Ensure 'Java version' is currently supported (if in use) - TBD # 2.2.2 Ensure 'Python version' is currently supported (if in use) - TBD # 2.2.3 Ensure 'PHP version' is currently supported (if in use) - TBD # 2.2.4 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # 2.2.5 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD # 2.2.6 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.2.7 Ensure 'HTTPS Only' is set to 'On' - TBD # 2.2.8 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.2.9 Ensure end-to-end TLS encryption is enabled - TBD # 2.2.10 Ensure 'Remote debugging' is set to 'Off' - TBD # 2.2.11 Ensure incoming client certificates are enabled and required (if in use) - TBD # 2.2.12 Ensure 'App Service authentication' is set to 'Enabled' - TBD # 2.2.13 Ensure managed identities are configured - TBD # 2.2.14 Ensure deployment slot is integrated with a virtual network - TBD # 2.2.15 Ensure configuration is routed through the virtual network integration - TBD # 2.2.16 Ensure all traffic is routed through the virtual network - TBD # 2.2.17 Ensure cross-origin resource sharing does not allow all origins - TBD # # 2.3 Function Apps # 2.3.1 Ensure 'Java version' is currently supported (if in use) - TBD # 2.3.2 Ensure 'Python version' is currently supported (if in use) - TBD # 2.3.3 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # 2.3.5 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.3.6 Ensure 'HTTPS Only' is set to 'On' - TBD # 2.3.7 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.3.8 Ensure end-to-end TLS encryption is enabled - TBD # 2.3.9 Ensure 'Remote debugging' is set to 'Off' - TBD # 2.3.10 Ensure incoming client certificates are enabled and required (if in use) - TBD # 2.3.11 Ensure 'App Service authentication' is set to 'Enabled' - TBD # 2.3.12 Ensure managed identities are configured - TBD # 2.3.13 Ensure public network access is disabled - TBD # 2.3.14 Ensure function app is integrated with a virtual network - TBD # 2.3.15 Ensure configuration is routed through the virtual network integration - TBD # 2.3.16 Ensure all traffic is routed through the virtual network - TBD # 2.3.17 Ensure cross-origin resource sharing does not allow all origins - TBD # # 2.4 Functions Deployment Slots # 2.4.1 Ensure 'Java version' is currently supported (if in use) - TBD # 2.4.2 Ensure 'Python version' is currently supported (if in use) - TBD # 2.4.3 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # 2.4.4 Ensure 'FTP state' is set to 'FTPS only' or 'Disabled' - TBD # 2.4.5 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.4.6 Ensure 'HTTPS Only' is set to 'On' - TBD # 2.4.7 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.4.8 Ensure end-to-end TLS encryption is enabled - TBD # 2.4.9 Ensure 'Remote debugging' is set to 'Off' - TBD # 2.4.10 Ensure incoming client certificates are enabled and required (if in use) - TBD # 2.4.11 Ensure managed identities are configured - TBD # 2.4.12 Ensure public network access is disabled - TBD # 2.4.13 Ensure deployment slot is integrated with a virtual network - TBD # 2.4.14 Ensure configuration is routed through the virtual network integration - TBD # 2.4.15 Ensure all traffic is routed through the virtual network - TBD # 2.4.16 Ensure cross-origin resource sharing does not allow all origins - TBD # 2.5 Ensure Azure Key Vaults are Used to Store Secrets - TBD # 2.6 Ensure App Service Environment is deployed with an internal load balancer - TBD # 2.7 Ensure App Service Environment is provisioned with v3 or higher - TBD # 2.8 Ensure App Service Environment has internal encryption enabled - TBD # 2.9 Ensure App Service Environment has TLS 1.0 and 1.1 disabled - TBD # # 3. Azure Container Instances # 3.1 Ensure Private Virtual Networks are used for Container Instances - TBD # 3.2 Ensure a Managed Identity is used for interactions with other Azure services - TBD # 3.3 Ensure the principle of least privilege is used when assigning roles to a Managed Identity - TBD # # 4. Azure CycleCloud # 4.1 Ensure SSL is configured for CycleCloud # # 5. Azure Dedicated Host # # 6. Azure Functions # # 7. Azure Kubernetes Service # # 8. Azure Quantum # # 9. Azure Service Fabric # # 10. Azure Spot Virtual Machines # # 11. Azure Spring Apps # # 12. Azure Virtual Desktop # # 13. Azure VM Image Builder # # 14. Azure VMware Solution # # 15. Azure Batch # 15.1 Ensure Batch account is set to use customer-managed keys to encrypt data - TBD # 15.2 Ensure Batch pools disk encryption is set enabled - TBD # 15.3 Ensure local authentication methods for accounts are disabled - TBD # 15.4 Ensure Private endpoints are considered for Batch accounts - TBD # 15.5 Ensure public network access is disabled for Batch accounts - TBD # 15.6 Ensure private DNS zones for private endpoints that connect to Batch accounts are configured - TBD # 15.7 Ensure Diagnostics settings logs for Batch accounts are enabled - TBD # # 16. Linux Virtual Machines # # 17. SQL Server on Azure Virtual Machines # # 18. Static Web Apps # # 19. VM Scale Sets # # 20. Virtual Machines # 20.1 Ensure Virtual Machines are utilizing Managed Disks # 20.2 Ensure that 'OS and Data' disks are encrypted with 'Customer Managed Key' (CMK) # 20.3 Ensure that 'Unattached disks' are encrypted with 'Customer Managed Key' (CMK) # 20.4 Ensure that 'Disk Network Access' is NOT set to 'Enable public access from all networks' # 20.5 Ensure that 'Enable Data Access Authentication Mode' is 'Checked' # 20.6 Ensure that Only Approved Extensions Are Installed # 20.7 Ensure that Endpoint Protection for all Virtual Machines is installed # 20.8 [Legacy] Ensure that VHDs are Encrypted # 20.9 Ensure only MFA enabled identities can access privileged Virtual Machine # 20.10 Ensure Trusted Launch is enabled on Virtual Machines # 20.11 Ensure that encryption at host is enabled # # Refer to Section(s) 2-20 Page(s) 22-341 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_compute_services () { print_function "audit_azure_compute_services" check_message "Azure Compute Services" audit_azure_app_service_apps audit_azure_app_service_deployment_slots audit_azure_function_apps audit_azure_function_deployment_slots audit_azure_key_vault_certificates audit_azure_key_vault_secrets audit_azure_app_service_ase audit_azure_container_instances audit_azure_cycle_cloud audit_azure_batch audit_azure_vms } ================================================ FILE: modules/azure/compute/vm/audit_azure_vms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_vms # # Check Azure Virtual Machines # # 20.1 Ensure Virtual Machines are utilizing Managed Disks # 20.2 Ensure that 'OS and Data' disks are encrypted with 'Customer Managed Key' (CMK) # 20.3 Ensure that 'Unattached disks' are encrypted with 'Customer Managed Key' (CMK) # 20.4 Ensure that 'Disk Network Access' is NOT set to 'Enable public access from all networks' # 20.5 Ensure that 'Enable Data Access Authentication Mode' is 'Checked' # 20.6 Ensure that Only Approved Extensions Are Installed # 20.7 Ensure that Endpoint Protection for all Virtual Machines is installed # 20.8 [Legacy] Ensure that VHDs are Encrypted # 20.9 Ensure only MFA enabled identities can access privileged Virtual Machine # 20.10 Ensure Trusted Launch is enabled on Virtual Machines # 20.11 Ensure that encryption at host is enabled # # Refer to Section(s) 20 Page(s) 307-41 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_vms () { print_function "audit_azure_vms" check_message "Azure Virtual Machines" } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_apps.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_apps # # Check Azure App Service Apps # # 2.1.1 Ensure 'Java version' is currently supported (if in use) - TBD # 2.1.2 Ensure 'Python version' is currently supported (if in use) - TBD # 2.1.3 Ensure 'PHP version' is currently supported (if in use) - TBD # 2.1.4 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # 2.1.5 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD # 2.1.6 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.1.7 Ensure 'HTTPS Only' is set to 'On' - TBD # 2.1.8 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.1.9 Ensure end-to-end TLS encryption is enabled - TBD # 2.1.10 Ensure 'Remote debugging' is set to 'Off' - TBD # 2.1.11 Ensure incoming client certificates are enabled and required (if in use) - TBD # 2.1.12 Ensure 'App Service authentication' is set to 'Enabled' - TBD # 2.1.13 Ensure managed identities are configured - TBD # 2.1.14 Ensure public network access is disabled - TBD # 2.1.15 Ensure App Service plan SKU supports private endpoints - TBD # 2.1.16 Ensure private endpoints are used to access App Service apps - TBD # 2.1.17 Ensure private endpoints used to access App Service apps use private DNS zones - TBD # 2.1.18 Ensure app is integrated with a virtual network - TBD # 2.1.19 Ensure configuration is routed through the virtual network integration - TBD # 2.1.20 Ensure all traffic is routed through the virtual network - TBD # 2.1.21 Ensure cross-origin resource sharing does not allow all origins - TBD # # Refer to Section(s) 2.1.1-21 Page(s) 23-89 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_apps () { print_function "audit_azure_app_service_apps" check_message "Azure App Service Apps" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Apps found" return fi # 2.1.1 Ensure 'Java version' is currently supported (if in use) - TBD audit_azure_app_service_java_versions # 2.1.2 Ensure 'Python version' is currently supported (if in use) - TBD audit_azure_app_service_python_versions # 2.1.3 Ensure 'PHP version' is currently supported (if in use) - TBD audit_azure_app_service_php_versions # 2.1.4 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD audit_azure_app_service_basic_authentication_publishing_credential_values # 2.1.5 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD audit_azure_app_service_ftp_states # 2.1.6 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.1.7 Ensure 'HTTPS Only' is set to 'On' - TBD audit_azure_app_service_http_values # 2.1.8 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.1.9 Ensure end-to-end TLS encryption is enabled - TBD audit_azure_app_service_tls_values # 2.1.10 Ensure 'Remote debugging' is set to 'Off' - TBD audit_azure_app_service_remote_debugging # 2.1.11 Ensure incoming client certificates are enabled and required (if in use) - TBD audit_azure_app_service_client_certificates # 2.1.12 Ensure 'App Service authentication' is set to 'Enabled' - TBD audit_azure_app_service_authentication # 2.1.13 Ensure managed identities are configured - TBD audit_azure_app_service_managed_identies # 2.1.14 Ensure public network access is disabled - TBD audit_azure_app_service_public_network_access # 2.1.16 Ensure private endpoints are used to access App Service apps - TBD audit_azure_app_service_private_endpoints # 2.1.17 Ensure private endpoints used to access App Service apps use private DNS zones - TBD audit_azure_app_service_private_dns_zones # 2.1.18 Ensure app is integrated with a virtual network - TBD audit_azure_app_service_virtual_network_integration # 2.1.19 Ensure configuration is routed through the virtual network integration - TBD # 2.1.20 Ensure all traffic is routed through the virtual network - TBD audit_azure_app_service_vnets # 2.1.21 Ensure cross-origin resource sharing does not allow all origins - TBD audit_azure_app_service_cross_origin_resource_sharing # 2.1.15 Ensure App Service plan SKU supports private endpoints - TBD audit_azure_app_service_plans } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_ases.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_ase # # Check Azure App Service ASE # # 2.6 Ensure App Service Environment is deployed with an internal load balancer - TBD # 2.7 Ensure App Service Environment is provisioned with v3 or higher - TBD # 2.8 Ensure App Service Environment has internal encryption enabled - TBD # 2.9 Ensure App Service Environment has TLS 1.0 and 1.1 disabled - TBD # 2.10 Ensure App Service Environment has TLS cipher suite ordering configured - TBD # # Refer to Section(s) 2.6-10 Page(s) 243-54 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_ase () { print_function "audit_azure_app_service_ase" check_message "Azure App Service ASE" command="az appservice ase list --query \"[].name\" --output tsv" command_message "${command}" ase_list=$( eval "${command}" 2> /dev/null ) if [ -z "${ase_list}" ]; then info_message "No App Service ASE found" fi for ase_name in ${ase_list}; do check_azure_app_service_ase_value "Deployed with an internal load balancer" "${ase_name}" "" "internalLoadBalancingMode" "ne" "None" check_azure_app_service_ase_value "Provisioned with ${azure_ase_version} or higher" "${ase_name}" "" "kind" "eq" "${azure_ase_version}" check_azure_app_service_ase_value "Internal encryption enabled" "${ase_name}" "clusterSettings" "internalEncryption" "eq" "true" check_azure_app_service_ase_value "TLS 1.0 disabled" "${ase_name}" "clusterSettings" "DisableTls1.0" "eq" "1" check_azure_app_service_ase_value "TLS 1.1 disabled" "${ase_name}" "clusterSettings" "DisableTls1.1" "eq" "1" for cipher_suite in "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" "TLS_AES_256_GCM_SHA384" "TLS_AES_128_GCM_SHA256"; do check_azure_app_service_ase_value "TLS cipher suite has ${cipher_suite}" "${ase_name}" "clusterSettings" "FrontEndSSLCipherSuiteOrder" "has" "${cipher_suite}" done done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_authentication.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_authentication # # Check Azure App Service Authentication # # 2.1.12 Ensure 'App Service authentication' is set to 'Enabled' - TBD # # Refer to Section(s) 2.1.12 Page(s) 60-2 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_authentication () { print_function "audit_azure_app_service_authentication" check_message "Azure App Service Authentication" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "App Service Auth v1" "${app_id}" "${app_name}" "${res_group}" "auth" "enabled" "eq" "true" "--enabled" "" check_azure_app_service_app_value "App Service Auth v2" "${app_id}" "${app_name}" "${res_group}" "auth" "platform.enabled" "eq" "true" "--enabled" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_basic_authentication_publishing_credential_values.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_basic_authentication_publishing_credential_values # # Check Azure App Service Basic Authentication Publishing Credential Values # # 2.1.4 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # # Refer to Section(s) 2.1.4 Page(s) 35-8 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_basic_authentication_publishing_credential_values () { print_function "audit_azure_app_service_basic_authentication_publishing_credential_values" check_message "Azure App Service Basic Authentication Publishing Credential Values" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_basic_authentication_publishing_credential_value "${app_name}" "${res_group}" "ftp" "Microsoft.Web" "basicPublishingCredentialsPolicies" "properties.allow" "eq" "false" "--auth-settings.publishing-credentials-enabled" "" check_azure_basic_authentication_publishing_credential_value "${app_name}" "${res_group}" "scm" "Microsoft.Web" "basicPublishingCredentialsPolicies" "properties.allow" "eq" "false" "--auth-settings.publishing-credentials-enabled" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_client_certificates.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_client_certificates # # Check Azure App Service Client Certificates # # 2.1.11 Ensure incoming client certificates are enabled and required (if in use) - TBD # # Refer to Section(s) 2.1.11 Page(s) 57-59 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_client_certificates () { print_function "audit_azure_app_service_client_certificates" check_message "Azure App Service Client Certificates" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Client Certificates" "${app_id}" "${app_name}" "${res_group}" "Microsoft.Web/sites" "clientCertEnabled" "eq" "true" "clientCertEnabled" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_cross_origin_resource_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_cross_origin_resource_sharing # # Check Azure App Service Cross-origin Resource sharing # # 2.1.21 Ensure cross-origin resource sharing does not allow all origins - TBD # # Refer to Section(s) 2.1.21 Page(s) 87-9 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_cross_origin_resource_sharing () { print_function "audit_azure_app_service_cross_origin_resource_sharing" check_message "Azure App Service Cross-Origin Resource Sharing" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Cross-Origin Resource Sharing" "${app_id}" "${app_name}" "${res_group}" "cors" "siteConfig.cors.allowedOrigins" "ne" "*" "properties.cors.allowedOrigins" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_ftp_states.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_ftp_states # # Check Azure App Service FTP States # # 2.1.5 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD # # Refer to Section(s) 2.1.5 Page(s) 39-41 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_ftp_states () { print_function "audit_azure_app_service_ftp_states" check_message "Azure App Service FTP States" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "FTP State" "${app_id}" "${app_name}" "${res_group}" "" "ftpState" "eq" "${azure_ftp_state}" "--ftp-state" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_http_logs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_http_logs # # Check Azure App Service HTTP Logs # # 6.1.1.6 Ensure that logging for Azure AppService 'HTTP logs' is enabled # # Refer to Section 6.1.1.6 Page(s) 213-4 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_http_logs () { print_function "audit_azure_app_service_http_logs" check_message "Azure App Service HTTP Logs" } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_http_values.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_http_values # # Check Azure App Service HTTP Values # # 2.1.6 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.1.7 Ensure 'HTTPS Only' is set to 'On' - TBD # # Refer to Section(s) 2.1.6-7 Page(s) 42-7 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_http_values () { print_function "audit_azure_app_service_http_values" check_message "Azure App Service HTTP Values" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "HTTP Version" "${app_id}" "${app_name}" "${res_group}" "" "http20Enabled" "eq" "true" "--http20-enabled" "" check_azure_app_service_app_value "HTTPS Only" "${app_id}" "${app_name}" "${res_group}" "" "httpsOnly" "eq" "true" "httpsOnly" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_java_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_java_versions # # Check Azure App Service Java Versions # # 2.1.1 Ensure 'Java version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.1.1 Page(s) 23-28 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_java_versions () { print_function "audit_azure_app_service_java_versions" check_message "Azure App Service Java Versions" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Java Version" "${app_id}" "${app_name}" "${res_group}" "" "javaVersion" "eq" "${azure_java_version}" "--java-version" "" check_azure_app_service_app_value "Java Container Version" "${app_id}" "${app_name}" "${res_group}" "" "javaContainerVersion" "eq" "${azure_java_version}" "--java-container-version" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_managed_identies.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_managed_identies # # Check Azure App Service Managed Identities # # 2.1.13 Ensure managed identities are configured - TBD # # Refer to Section(s) 2.1.13 Page(s) 63-5 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_managed_identies () { print_function "audit_azure_app_service_managed_identies" check_message "Azure App Service Managed Identities" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Managed Identities" "${app_id}" "${app_name}" "${res_group}" "identity" "type" "eq" "${azure_managed_identity}" "" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_php_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_php_versions # # Check Azure App Service PHP Versions # # 2.1.3 Ensure 'PHP version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.1.3 Page(s) 32-4 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_php_versions () { print_function "audit_azure_app_service_php_versions" check_message "Azure App Service PHP Versions" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "PHP Version" "${app_id}" "${app_name}" "${res_group}" "" "phpVersion" "eq" "${azure_php_version}" "--php-version" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_plans.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_plans # # Check Azure App Service Plans # # 2.1.15 Ensure App Service plan SKU supports private endpoints - TBD # # Refer to Section(s) 2.1.15 Page(s) 69-72 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_plans () { print_function "audit_azure_app_service_plans" check_message "Azure App Service Plans" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"appServicePlanId\" --output tsv" command_message "${command}" app_plans=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) if [ -z "${app_plans}" ]; then info_message "No App Service Plans found" return fi for app_plan in ${app_plans}; do check_azure_app_service_plan_value "${app_plan}" "${res_group}" "sku.tier" "eq" "${azure_sku_tier}" "--sku" "" done done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_private_dns_zones.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_private_dns_zones # # Check Azure App Service Private DNS Zones # # 2.1.17 Ensure private endpoints used to access App Service apps use private DNS zones - TBD # # Refer to Section(s) 2.1.17 Page(s) 69-72 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_private_dns_zones () { print_function "audit_azure_app_service_private_dns_zones" check_message "Azure App Service Private DNS Zones" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Private DNS Zones" "${app_id}" "${app_name}" "${res_group}" "Microsoft.Web/sites" "dnsConfiguration.dnsServers" "ne" "" "" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_private_endpoints.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_private_endpoints # # Check Azure App Service Private Endpoints # # 2.1.16 Ensure private endpoints are used to access App Service apps - TBD # # Refer to Section(s) 2.1.16 Page(s) 73-5 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_private_endpoints () { print_function "audit_azure_app_service_private_endpoints" check_message "Azure App Service Private Endpoints" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do check_azure_network_private_endpoint_value "${app_id}" "[*].privateLinkServiceConnections[*].[privateLinkServiceId,privateLinkServiceConnectionState.status]" "eq" "Approved" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_public_network_access.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_public_network_access # # Check Azure App Service Public Network Access # # 2.1.14 Ensure public network access is disabled - TBD # # Refer to Section(s) 2.1.14 Page(s) 66-8 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_public_network_access () { print_function "audit_azure_app_service_public_network_access" check_message "Azure App Service Public Network Access" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Public Network Access" "${app_id}" "${app_name}" "${res_group}" "" "publicNetworkAccess" "eq" "Disabled" "properties.publicNetworkAccess" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_python_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_python_versions # # Check Azure App Service Python Versions # # 2.1.2 Ensure 'Python version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.1.2 Page(s) 29-31 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_python_versions () { print_function "audit_azure_app_service_python_versions" check_message "Azure App Service Python Versions" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Python Version" "${app_id}" "${app_name}" "${res_group}" "" "pythonVersion" "eq" "${azure_python_version}" "--python-version" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_remote_debugging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_remote_debugging # # Check Azure App Service Remote Debugging # # 2.1.10 Ensure 'Remote debugging' is set to 'Off' - TBD # # Refer to Section(s) 2.1.10 Page(s) 54-6 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_remote_debugging () { print_function "audit_azure_app_service_remote_debugging" check_message "Azure App Service Remote Debugging" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Remote Debugging" "${app_id}" "${app_name}" "${res_group}" "" "remoteDebuggingEnabled" "eq" "false" "--remote-debugging-enabled" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_tls_values.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_tls_values # # Check Azure App Service TLS Values # # 2.1.8 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.1.9 Ensure end-to-end TLS encryption is enabled - TBD # # Refer to Section(s) 2.1.8-9 Page(s) 48-53 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_tls_values () { print_function "audit_azure_app_service_tls_values" check_message "Azure App Service TLS Values" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Minimum Inbound TLS Version" "${app_id}" "${app_name}" "${res_group}" "" "minTlsVersion" "eq" "1.2" "--min-tls-version" "" check_azure_app_service_app_value "End-to-End TLS Encryption" "${app_id}" "${app_name}" "${res_group}" "Microsoft.Web/sites" "endToEndEncryptionEnabled" "eq" "true" "properties.endToEndEncryptionEnabled" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_virtual_network_integration.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_virtual_network_integration # # Check Azure App Service Virtual Network Integration # # 2.1.18 Ensure app is integrated with a virtual network - TBD # # Refer to Section(s) 2.1.18 Page(s) 78-81 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_virtual_network_integration () { print_function "audit_azure_app_service_virtual_network_integration" check_message "Azure App Service Virtual Network Integration" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "Virtual Network Integration" "${app_id}" "${app_name}" "${res_group}" "" "virtualNetworkSubnetId" "ne" "" "" "" done } ================================================ FILE: modules/azure/compute/webapp/apps/audit_azure_app_service_vnets.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_vnets # # Check Azure App Service VNets # # 2.1.19 Ensure configuration is routed through the virtual network integration - TBD # 2.1.20 Ensure all traffic is routed through the virtual network - TBD # # Refer to Section(s) 2.1.19-20 Page(s) 82-86 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_vnets () { print_function "audit_azure_app_service_vnets" check_message "Azure App Service VNets" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Services found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) check_azure_app_service_app_value "VNet Image Pull" "${app_id}" "${app_name}" "${res_group}" "Microsoft.Web/sites" "vnetRouteAllEnabled" "eq" "true" "properties.vnetRouteAllEnabled" "" check_azure_app_service_app_value "VNet Content Share" "${app_id}" "${app_name}" "${res_group}" "Microsoft.Web/sites" "vnetContentShareEnabled" "eq" "true" "properties.vnetContentShareEnabled" "" done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots # # App Service Deployment Slots # 2.2.1 Ensure 'Java version' is currently supported (if in use) - TBD # 2.2.2 Ensure 'Python version' is currently supported (if in use) - TBD # 2.2.3 Ensure 'PHP version' is currently supported (if in use) - TBD # 2.2.4 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # 2.2.5 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD # 2.2.6 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.2.7 Ensure 'HTTPS Only' is set to 'On' - TBD # 2.2.8 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.2.9 Ensure end-to-end TLS encryption is enabled - TBD # 2.2.10 Ensure 'Remote debugging' is set to 'Off' - TBD # 2.2.11 Ensure incoming client certificates are enabled and required (if in use) - TBD # 2.2.12 Ensure managed identities are configured - TBD # 2.2.13 Ensure public network access is disabled - TBD # 2.2.14 Ensure deployment slot is integrated with a virtual network - TBD # 2.2.15 Ensure configuration is routed through the virtual network integration - TBD # 2.2.16 Ensure all traffic is routed through the virtual network - TBD # 2.2.17 Ensure cross-origin resource sharing does not allow all origins - TBD # # Refer to Section(s) 2.2.1-17 Page(s) 90-141 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots () { print_function "audit_azure_app_service_deployment_slots" check_message "Azure App Service Deployment Slots" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Apps found" return fi # 2.2.1 Ensure 'Java version' is currently supported (if in use) - TBD audit_azure_app_service_deployment_slots_java_versions # 2.2.2 Ensure 'Python version' is currently supported (if in use) - TBD audit_azure_app_service_deployment_slots_python_versions # 2.2.3 Ensure 'PHP version' is currently supported (if in use) - TBD audit_azure_app_service_deployment_slots_php_versions # 2.2.4 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD audit_azure_app_service_deployment_slots_basic_auth # 2.2.5 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD audit_azure_app_service_deployment_slots_ftp_states # 2.2.6 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.2.7 Ensure 'HTTPS Only' is set to 'On' - TBD audit_azure_app_service_deployment_slots_http_values # 2.2.8 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # 2.2.9 Ensure end-to-end TLS encryption is enabled - TBD audit_azure_app_service_deployment_slots_tls_values # 2.2.10 Ensure 'Remote debugging' is set to 'Off' - TBD audit_azure_app_service_deployment_slots_remote_debugging # 2.2.11 Ensure incoming client certificates are enabled and required (if in use) - TBD audit_azure_app_service_deployment_slots_client_certificates # 2.2.12 Ensure managed identities are configured - TBD audit_azure_app_service_deployment_slots_managed_identities # 2.2.13 Ensure public network access is disabled - TBD audit_azure_app_service_deployment_slots_public_network_access # 2.2.14 Ensure app is integrated with a virtual network - TBD # 2.2.15 Ensure configuration is routed through the virtual network integration - TBD audit_azure_app_service_deployment_slots_virtual_network_integration # 2.2.17 Ensure cross-origin resource sharing does not allow all origins - TBD audit_azure_app_service_deployment_slots_cross_origin_resource_sharing # 2.2.16 Ensure private endpoints are used to access App Service apps - TBD audit_azure_app_service_deployment_slots_private_endpoints } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_basic_authentication_publishing_credentials.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_basic_authentication_publishing_credentials # # 2.2.4 Ensure 'Basic Authentication Publishing Credentials' are 'Disabled' - TBD # # Refer to Section(s) 2.2.4 Page(s) 100-3 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_basic_authentication_publishing_credentials () { print_function "audit_azure_app_service_deployment_slots_basic_authentication_publishing_credentials" check_message "Azure App Service Deployment Slot Basic Authentication Publishing Credentials" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Basic Authentication Publishing Credentials" "${slot_id}" "${app_name}" "${res_group}" "basicPublishingCredentialsPolicies" "ftp" "Microsoft.Web/sites" "properties.allow" "eq" "false" "" "" check_azure_app_service_deployment_slot_value "Basic Authentication Publishing Credentials" "${slot_id}" "${app_name}" "${res_group}" "basicPublishingCredentialsPolicies" "scm" "Microsoft.Web/sites" "properties.allow" "eq" "false" "" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_client_certificates.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_client_certificates # # 2.2.11 Ensure incoming client certificates are enabled and required (if in use) - TBD # # Refer to Section(s) 2.2.11 Page(s) 122-4 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_client_certificates () { print_function "audit_azure_app_service_deployment_slots_client_certificates" check_message "Azure App Service Deployment Slot Client Certificates" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Client Certificates" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "clientCertEnabled" "eq" "true" "clientCertEnabled" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_cross_origin_resource_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_cross_origin_resource_sharing # # 2.2.17 Ensure cross-origin resource sharing does not allow all origins - TBD # # Refer to Section(s) 2.2.17 Page(s) 139-41 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_cross_origin_resource_sharing () { print_function "audit_azure_app_service_deployment_slots_cross_origin_resource_sharing" check_message "Azure App Service Deployment Slot Cross-Origin Resource Sharing" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Cross-Origin Resource Sharing" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "cors" "siteConfig.cors.allowedOrigins" "ne" "*" "properties.cors.allowedOrigins" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_ftp_states.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_ftp_states # # 2.2.5 Ensure 'FTP State' is set to 'FTPS only' or 'Disabled' - TBD # # Refer to Section(s) 2.2.5 Page(s) 104-6 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_ftp_states () { print_function "audit_azure_app_service_deployment_slots_ftp_states" check_message "Azure App Service Deployment Slot FTP States" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "FTP State" "${slot_id}" "${app_name}" "${res_group}" "config" "ftp" "Microsoft.Web/sites" "ftpState" "eq" "${azure_ftp_state}" "--ftp-state" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_http_values.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_http_versions # # 2.2.6 Ensure 'HTTP version' is set to '2.0' (if in use) - TBD # 2.2.7 Ensure 'HTTPS Only' is set to 'On' - TBD # # Refer to Section(s) 2.2.6 Page(s) 107-12 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_http_versions () { print_function "audit_azure_app_service_deployment_slots_http_versions" check_message "Azure App Service Deployment Slot HTTP Versions" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "HTTP Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "http20Enabled" "eq" "true" "--http20-enabled" "" check_azure_app_service_deployment_slot_value "HTTPS Only" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "httpsOnly" "eq" "true" "httpsOnly" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_java_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_java_versions # # 2.2.1 Ensure 'Java version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.2.1 Page(s) 91-93 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_java_versions () { print_function "audit_azure_app_service_deployment_slots_java_versions" check_message "Azure App Service Deployment Slot Java Versions" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Java Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "javaVersion" "eq" "${azure_java_version}" "--java-version" "" check_azure_app_service_deployment_slot_value "Java Container Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "javaContainerVersion" "eq" "${azure_java_version}" "--java-container-version" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_managed_identities.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_managed_identities # # 2.2.12 Ensure managed identities are configured - TBD # # Refer to Section(s) 2.2.12 Page(s) 125-7 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_managed_identities () { print_function "audit_azure_app_service_deployment_slots_managed_identities" check_message "Azure App Service Deployment Slot Managed Identities" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Managed Identities" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "identity" "type" "eq" "${azure_managed_identity}" "" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_php_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_php_versions # # 2.2.3 Ensure 'PHP version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.2.3 Page(s) 97-99 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_php_versions () { print_function "audit_azure_app_service_deployment_slots_php_versions" check_message "Azure App Service Deployment Slot PHP Versions" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "PHP Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "phpVersion" "eq" "${azure_php_version}" "--php-version" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_private_endpoints.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_private_endpoints # # 2.2.16 Ensure private endpoints are used to access App Service apps - TBD # # Refer to Section(s) 2.2.16 Page(s) 136-8 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_private_endpoints () { print_function "audit_azure_app_service_deployment_slots_private_endpoints" check_message "Azure App Service Deployment Slot Private Endpoints" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) for app_id in ${app_ids}; do check_azure_network_private_endpoint_value "${app_id}" "[*].privateLinkServiceConnections[*].[privateLinkServiceId,privateLinkServiceConnectionState.status]" "eq" "Approved" done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_public_network_access.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_public_network_access # # 2.2.13 Ensure public network access is disabled - TBD # # Refer to Section(s) 2.2.13 Page(s) 128-30 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_public_network_access () { print_function "audit_azure_app_service_deployment_slots_public_network_access" check_message "Azure App Service Deployment Slot Public Network Access" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Public Network Access" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "publicNetworkAccess" "eq" "Disabled" "properties.publicNetworkAccess" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_python_versions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_python_versions # # 2.2.2 Ensure 'Python version' is currently supported (if in use) - TBD # # Refer to Section(s) 2.2.2 Page(s) 94-96 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_python_versions () { print_function "audit_azure_app_service_deployment_slots_python_versions" check_message "Azure App Service Deployment Slot Python Versions" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Python Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "pythonVersion" "eq" "${azure_python_version}" "--python-version" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_remote_debugging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_remote_debugging # # 2.2.10 Ensure 'Remote debugging' is set to 'Off' - TBD # # Refer to Section(s) 2.2.10 Page(s) 119-21 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_remote_debugging () { print_function "audit_azure_app_service_deployment_slots_remote_debugging" check_message "Azure App Service Deployment Slot Remote Debugging" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Remote Debugging" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "remoteDebuggingEnabled" "eq" "false" "--remote-debugging-enabled" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_tls_values.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_tls_values # # 2.2.8 Ensure 'Minimum Inbound TLS Version' is set to '1.2' or higher - TBD # # Refer to Section(s) 2.2.8 Page(s) 113-8 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_tls_values () { print_function "audit_azure_app_service_deployment_slots_tls_values" check_message "Azure App Service Deployment Slot TLS Values" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Minimum Inbound TLS Version" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "minTlsVersion" "eq" "1.2" "--min-tls-version" "" check_azure_app_service_deployment_slot_value "End-to-End TLS Encryption" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "endToEndEncryptionEnabled" "eq" "true" "properties.endToEndEncryptionEnabled" "" done done } ================================================ FILE: modules/azure/compute/webapp/slots/audit_azure_app_service_deployment_slots_virtual_network_integration.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_app_service_deployment_slots_virtual_network_integration # # 2.2.14 Ensure app is integrated with a virtual network - TBD # 2.2.15 Ensure configuration is routed through the virtual network integration - TBD # # Refer to Section(s) 2.2.14-5 Page(s) 131-5 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_app_service_deployment_slots_virtual_network_integration () { print_function "audit_azure_app_service_deployment_slots_virtual_network_integration" check_message "Azure App Service Deployment Slot Virtual Network Integration" command="az webapp list --query \"[].id\" --output tsv" command_message "${command}" app_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${app_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for app_id in ${app_ids}; do command="az webapp show --id \"${app_id}\" --query \"name\" --output tsv" command_message "${command}" app_name=$( eval "${command}" ) command="az webapp show --id \"${app_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az webapp deployment slot list --id \"${app_id}\" --query \"[].id\" --output tsv" command_message "${command}" slot_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${slot_ids}" ]; then info_message "No App Service Deployment Slots found" return fi for slot_id in ${slot_ids}; do check_azure_app_service_deployment_slot_value "Virtual Network Integration" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "virtualNetworkSubnetId" "ne" "" "" "" check_azure_app_service_deployment_slot_value "VNet Image Pull" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "vnetRouteAllEnabled" "eq" "true" "properties.vnetRouteAllEnabled" "" check_azure_app_service_deployment_slot_value "VNet Content Share" "${slot_id}" "${app_name}" "${res_group}" "config" "web" "Microsoft.Web/sites" "vnetContentShareEnabled" "eq" "true" "properties.vnetContentShareEnabled" "" done done } ================================================ FILE: modules/azure/database/audit_azure_cosmos_db.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_cosmos_db # # Check Azure Cosmos DB # # 3.1 Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks # 3.2 Ensure that Cosmos DB uses Private Endpoints where possible # 3.3 Ensure that 'disableLocalAuth' is set to 'true' # 3.4 Ensure `Public Network Access` is `Disabled` # 3.5 Ensure critical data is encrypted with customer-managed keys (CMK) # 3.6 Ensure the firewall does not allow all network traffic # 3.7 Ensure that Cosmos DB Logging is Enabled # # Refer to Section(s) 3 Page(s) 51-72 Microsoft Azure Database Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_cosmos_db () { print_function "audit_azure_cosmos_db" check_message "Azure Cosmos DB" command="az cosmosdb list --query \"[].name\" --output tsv" command_message "${command}" db_names=$( eval "${command}" ) if [ -z "${db_names}" ]; then info_message "No Cosmos DB instances found" return fi for db_name in ${db_names}; do command="az cosmosdb show --name \"${db_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 3.1 Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks check_cosmos_db_value "Firewalls & Networks Filter" "${db_name}" "${res_group}" "isVirtualNetworkFilterEnabled" "eq" "true" "" "" check_cosmos_db_value "Firewalls & Networks IP Rules" "${db_name}" "${res_group}" "ipRules" "ne" "" "" "" # 3.2 Ensure that Cosmos DB uses Private Endpoints where possible check_cosmos_db_value "Private Endpoints" "${db_name}" "${res_group}" "privateEndpointConnections" "ne" "" "" "" # 3.3 Ensure that 'disableLocalAuth' is set to 'true' check_cosmos_db_value "Disable Local Auth" "${db_name}" "${res_group}" "disableLocalAuth" "eq" "true" "properties.disableLocalAuth" "" # 3.4 Ensure `Public Network Access` is `Disabled` check_cosmos_db_value "Public Network Access" "${db_name}" "${res_group}" "publicNetworkAccess" "eq" "Disabled" "" "" # 3.5 Ensure critical data is encrypted with customer-managed keys (CMK) check_cosmos_db_value "Customer-Managed Keys" "${db_name}" "${res_group}" "keyVaultKeyUri" "ne" "" "" "" # 3.6 Ensure the firewall does not allow all network traffic check_cosmos_db_value "Firewalls & Networks IP Rules" "${db_name}" "${res_group}" "ipRules" "ne" "0.0.0.0" "--ip-range-filter" "comma-separated-list-of-allowed-ip-addresses" done command="az cosmosdb list --query \"[].id\" --output tsv" command_message "${command}" res_ids=$( eval "${command}" ) for res_id in ${res_ids}; do check_azure_monitoring_diagnostics_value "${res_id}" done } ================================================ FILE: modules/azure/database/audit_azure_mysql_db.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_mysql_db # # Check Azure Database for MySQL # # Azure Database for MySQL # 5.1 Ensure Azure Database for MySQL uses Customer Managed Keys for Encryption at Rest - TBD # 5.2 Ensure Azure Database for MySQL uses only Microsoft Entra Authentication - TBD # 5.3 Ensure `Public Network Access` is `Disabled` for Azure Database for MySQL - TBD # 5.4 Ensure Private Endpoints Are Used for Azure MySQL Databases - TBD # 5.5 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL flexible server - TBD # 5.6 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL flexible server - TBD # 5.7 Ensure server parameter 'error_server_log_file' is Enabled for MySQL Database Server - TBD # 5.8 Ensure server parameter 'require_secure_transport' is set to 'ON' for MySQL Server - TBD # 5.9 Ensure server parameter 'tls_version' is set to 'TLSv1.2' (or higher) for MySQL flexible server - TBD # # Refer to Section(s) 5 Page(s) 84-105 Microsoft Azure Database Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_mysql_db () { print_function "audit_azure_mysql_db" check_message "Azure Database for MySQL" command="az mysql server list --query \"[].name\" --output tsv" command_message "${command}" mysql_servers=$( eval "${command}" ) if [ "${mysql_servers}" = "" ]; then info_message "No MySQL servers found" else for mysql_server in ${mysql_servers}; do command="az mysql server show --name ${mysql_server} --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 5.1 Ensure Azure Database for MySQL uses Customer Managed Keys for Encryption at Rest - TBD check_mysql_db_value "Customer-Managed Keys" "server" "${mysql_server}" "${res_group}" "" "keyVaultKeyUri" "ne" "" "" "" # 5.2 Ensure Azure Database for MySQL uses only Microsoft Entra Authentication - TBD # check_mysql_db_value "Microsoft Entra Authentication" "server" "${mysql_server}" "${res_group}" "" "" "" "" "" "" # 5.3 Ensure `Public Network Access` is `Disabled` for Azure Database for MySQL - TBD check_mysql_db_value "Public Network Access" "server" "${mysql_server}" "${res_group}" "" "publicNetworkAccess" "eq" "Disabled" "" "" # 5.4 Ensure Private Endpoints Are Used for Azure MySQL Databases - TBD check_mysql_db_value "Private Endpoints" "server" "${mysql_server}" "${res_group}" "" "privateEndpointConnections" "ne" "" "" "" # 5.5 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL server - TBD # check_mysql_db_value "Audit Log" "server" "${mysql_server}" "${res_group}" "" "audit_log_enabled" "eq" "ON" "" "" # 5.6 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL server - TBD # check_mysql_db_value "Audit Log Events" "server" "${mysql_server}" "${res_group}" "" "audit_log_events" "eq" "CONNECTION" "" "" # 5.7 Ensure server parameter 'error_server_log_file' is Enabled for MySQL Database Server - TBD # check_mysql_db_value "Error Server Log File" "server" "${mysql_server}" "${res_group}" "" "error_server_log_file" "eq" "Enabled" "" "" # 5.8 Ensure server parameter 'require_secure_transport' is set to 'ON' for MySQL Server - TBD # check_mysql_db_value "Require Secure Transport" "server" "${mysql_server}" "${res_group}" "" "require_secure_transport" "eq" "ON" "" "" # 5.9 Ensure server parameter 'tls_version' is set to 'TLSv1.2' (or higher) for MySQL flexible server - TBD # check_mysql_db_value "TLS Version" "server" "${mysql_server}" "${res_group}" "" "tls_version" "eq" "TLSv1.2" "" "" done fi command="az mysql flexible-server list --query \"[].name\" --output tsv" command_message "${command}" mysql_servers=$( eval "${command}" ) if [ "${mysql_servers}" = "" ]; then info_message "No MySQL flexible servers found" else for mysql_server in ${mysql_servers}; do command="az mysql flexible-server show --server-name ${mysql_server} --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az mysql flexible-server db list --server-name ${mysql_server} --resource-group ${res_group} --query \"[].name\" --output tsv" command_message "${command}" db_names=$( eval "${command}" ) for db_name in ${db_names}; do # 5.1 Ensure Azure Database for MySQL uses Customer Managed Keys for Encryption at Rest - TBD check_mysql_db_value "Customer-Managed Keys" "flexible-server" "${mysql_server}" "${res_group}" "${db_name}" "keyVaultKeyUri" "ne" "" "" "" # 5.2 Ensure Azure Database for MySQL uses only Microsoft Entra Authentication - TBD # check_mysql_db_value "Microsoft Entra Authentication" "flexible-server" "${mysql_server}" "${res_group}" "${db_name}" "" "" "" "" "" # 5.3 Ensure `Public Network Access` is `Disabled` for Azure Database for MySQL - TBD check_mysql_db_value "Public Network Access" "flexible-server" "${mysql_server}" "${res_group}" "${db_name}" "publicNetworkAccess" "eq" "Disabled" "" "" # 5.4 Ensure Private Endpoints Are Used for Azure MySQL Databases - TBD check_mysql_db_value "Private Endpoints" "flexible-server" "${mysql_server}" "${res_group}" "${db_name}" "privateEndpointConnections" "ne" "" "" "" # 5.5 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL flexible server - TBD # check_mysql_db_value "Audit Log" "flexible-server" "${mysql_server}" "${res_group}" "${db_name}" "audit_log_enabled" "eq" "ON" "" "" # 5.6 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL flexible server - TBD # check_mysql_db_value "Audit Log Events" "flexible-server" "${mysql_server}" "${res_group}" "${db_name}" "audit_log_events" "eq" "CONNECTION" "" "" # 5.7 Ensure server parameter 'error_server_log_file' is Enabled for MySQL Database Server - TBD # check_mysql_db_value "Error Server Log File" "flexible-server" "${mysql_server}" "${res_group}" "${db_name}" "error_server_log_file" "eq" "Enabled" "" "" # 5.8 Ensure server parameter 'require_secure_transport' is set to 'ON' for MySQL Server - TBD # check_mysql_db_value "Require Secure Transport" "flexible-server" "${mysql_server}" "${res_group}" "${db_name}" "require_secure_transport" "eq" "ON" "" "" # 5.9 Ensure server parameter 'tls_version' is set to 'TLSv1.2' (or higher) for MySQL flexible server - TBD # check_mysql_db_value "TLS Version" "flexible-server" "${mysql_server}" "${res_group}" "${db_name}" "tls_version" "eq" "TLSv1.2" "" "" done done fi } ================================================ FILE: modules/azure/database/audit_azure_postgresql_db.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_postgresql_db # # Check Azure Database for PostgreSQL # # Azure Database for PostgreSQL # 6.1 Ensure Azure Database for PostgreSQL uses Customer Managed Keys for Encryption at Rest - TBD # 6.2 Ensure Azure Database for PostgreSQL uses only Microsoft Entra Authentication - TBD # 6.3 Ensure `Public Network Access` is `Disabled` for Azure Database for PostgreSQL - TBD # 6.4 Ensure Private Endpoints Are Used for Azure PostgreSQL Databases - TBD # 6.5 Ensure server parameter 'connection_throttle.enable' is set to 'ON' for PostgreSQL server - TBD # 6.6 Ensure server parameter 'logfiles.retention_days' is greater than 3 days for PostgreSQL server - TBD # 6.7 Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL server - TBD # 6.8 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL servers - TBD # 6.9 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL servers - TBD # 6.10 Ensure server parameter 'require_secure_transport' is set to 'ON' for PostgreSQL server - TBD # 6.11 Ensure server parameter 'tls_version' is set to 'TLSv1.2' (or higher) for PostgreSQL server - TBD # # Refer to Section(s) 6 Page(s) 106-138 Microsoft Azure Database Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_postgresql_db () { print_function "audit_azure_postgresql_db" check_message "Azure Database for PostgreSQL" command="az postgresql server list --query \"[].name\" --output tsv" command_message "${command}" sql_servers=$( eval "${command}" ) if [ "${sql_servers}" = "" ]; then info_message "No PostgreSQL servers found" else for sql_server in ${sql_servers}; do command="az postgresql server show --name ${sql_server} --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 6.1 Ensure Azure Database for PostgreSQL uses Customer Managed Keys for Encryption at Rest - TBD check_postgresql_db_value "Customer-Managed Keys" "server" "${sql_server}" "${res_group}" "" "keyVaultKeyUri" "ne" "" "" "" # 6.2 Ensure Azure Database for PostgreSQL uses only Microsoft Entra Authentication - TBD # check_postgresql_db_value "Microsoft Entra Authentication" "server" "${sql_server}" "${res_group}" "" "" "" "" "" "" # 6.3 Ensure `Public Network Access` is `Disabled` for Azure Database for PostgreSQL - TBD check_postgresql_db_value "Public Network Access" "server" "${sql_server}" "${res_group}" "" "publicNetworkAccess" "eq" "Disabled" "" "" # 6.4 Ensure Private Endpoints Are Used for Azure PostgreSQL Databases - TBD check_postgresql_db_value "Private Endpoints" "server" "${sql_server}" "${res_group}" "" "privateEndpointConnections" "ne" "" "" "" # 6.5 Ensure server parameter 'connection_throttle.enable' is set to 'ON' for PostgreSQL server - TBD # check_postgresql_db_value "Connection Throttle" "server" "${sql_server}" "${res_group}" "" "connection_throttle.enable" "eq" "ON" "" "" # 6.6 Ensure server parameter 'logfiles.retention_days' is greater than 3 days for PostgreSQL server - TBD # check_postgresql_db_value "Log Retention" "server" "${sql_server}" "${res_group}" "" "logfiles.retention_days" "gt" "3" "" "" # 6.7 Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL server - TBD # check_postgresql_db_value "Log Checkpoints" "server" "${sql_server}" "${res_group}" "" "log_checkpoints" "eq" "ON" "" "" # 6.8 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL servers - TBD # check_postgresql_db_value "Log Disconnections" "server" "${sql_server}" "${res_group}" "" "log_disconnections" "eq" "ON" "" "" # 6.9 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL servers - TBD # check_postgresql_db_value "Log Connections" "server" "${sql_server}" "${res_group}" "" "log_connections" "eq" "ON" "" "" # 6.10 Ensure server parameter 'require_secure_transport' is set to 'ON' for PostgreSQL server - TBD # check_postgresql_db_value "Require Secure Transport" "server" "${sql_server}" "${res_group}" "" "require_secure_transport" "eq" "ON" "" "" # 6.11 Ensure server parameter 'tls_version' is set to 'TLSv1.2' (or higher) for PostgreSQL server - TBD # check_postgresql_db_value "TLS Version" "server" "${sql_server}" "${res_group}" "" "tls_version" "eq" "TLSv1.2" "" "" done fi command="az postgresql flexible-server list --query \"[].name\" --output tsv" command_message "${command}" f_servers=$( eval "${command}" ) if [ "${f_servers}" = "" ]; then info_message "No PostgreSQL flexible servers found" else for f_server in ${f_servers}; do command="az postgresql flexible-server show --server-name ${f_server} --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az postgresql flexible-server db list --server-name ${f_server} --resource-group ${res_group} --query \"[].name\" --output tsv" command_message "${command}" db_names=$( eval "${command}" ) for db_name in ${db_names}; do # 6.1 Ensure Azure Database for MySQL uses Customer Managed Keys for Encryption at Rest - TBD check_postgresql_db_value "Customer-Managed Keys" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "keyVaultKeyUri" "ne" "" "" "" # 6.2 Ensure Azure Database for MySQL uses only Microsoft Entra Authentication - TBD # check_postgresql_db_value "Microsoft Entra Authentication" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "" "" "" "" "" # 6.3 Ensure `Public Network Access` is `Disabled` for Azure Database for MySQL - TBD check_postgresql_db_value "Public Network Access" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "publicNetworkAccess" "eq" "Disabled" "" "" # 6.4 Ensure Private Endpoints Are Used for Azure MySQL Databases - TBD check_postgresql_db_value "Private Endpoints" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "privateEndpointConnections" "ne" "" "" "" # 6.5 Ensure server parameter 'connection_throttle.enable' is set to 'ON' for PostgreSQL server - TBD # check_postgresql_db_value "Connection Throttle" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "connection_throttle.enable" "eq" "ON" "" "" # 6.6 Ensure server parameter 'logfiles.retention_days' is greater than 3 days for PostgreSQL server - TBD # check_postgresql_db_value "Log Retention" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "logfiles.retention_days" "gt" "3" "" "" # 6.7 Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL server - TBD # check_postgresql_db_value "Log Checkpoints" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "log_checkpoints" "eq" "ON" "" "" # 6.8 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL servers - TBD # check_postgresql_db_value "Log Disconnections" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "log_disconnections" "eq" "ON" "" "" # 6.9 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL servers - TBD # check_postgresql_db_value "Log Connections" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "log_connections" "eq" "ON" "" "" # 6.10 Ensure server parameter 'require_secure_transport' is set to 'ON' for PostgreSQL server - TBD # check_postgresql_db_value "Require Secure Transport" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "require_secure_transport" "eq" "ON" "" "" # 6.11 Ensure server parameter 'tls_version' is set to 'TLSv1.2' (or higher) for PostgreSQL server - TBD # check_postgresql_db_value "TLS Version" "flexible-server" "${f_server}" "${res_group}" "${db_name}" "tls_version" "eq" "TLSv1.2" "" "" done done fi } ================================================ FILE: modules/azure/database/audit_azure_redis_cache.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_database_services # # Check Azure Database Services # # Refer to Section(s) 4 Page(s) 69 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to CIS Microsoft Azure Database Services Benchmark # # 2.2 Ensure that 'Allow access only via SSL' is set to 'Yes' # 2.3 Ensure that 'Minimum TLS version' is set to TLS v1.2 (or higher) # 2.6 Ensure that 'Public Network Access' is 'Disabled' # 2.7 Ensure Azure Cache for Redis is Using a Private Link # 2.8 Ensure that Azure Cache for Redis is Using Customer-Managed Keys # 2.9 Ensure 'Access Keys Authentication' is set to 'Disabled' # 2.10 Ensure 'Update Channel' is set to 'Stable' # # Refer to Section(s) 2 Page(s) 11-12 Microsoft Azure Database Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_redis_cache () { print_function "audit_azure_redis_cache" check_message "Azure Redis Cache" command="az redis list --query \"[].name\" --output tsv" command_message "${command}" redis_names=$( eval "${command}" ) if [ -z "${redis_names}" ]; then info_message "No Redis instances found" return fi for redis_name in ${redis_names}; do command="az redis show --name \"${redis_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 2.2 Ensure that 'Allow access only via SSL' is set to 'Yes' check_redis_cache_value "Allow access only via SSL" "${redis_name}" "${res_group}" "sslEnabled" "eq" "true" "enableSsl" # 2.3 Ensure that 'Minimum TLS version' is set to TLS v1.2 (or higher) check_redis_cache_value "Minimum TLS version" "${redis_name}" "${res_group}" "minimumTlsVersion" "eq" "1.2" "--minimum-tls-version" # 2.6 Ensure that 'Public Network Access' is 'Disabled' check_redis_cache_value "Public Network Access" "${redis_name}" "${res_group}" "publicNetworkAccess" "eq" "disabled" "--public-network-access" # 2.7 Ensure Azure Cache for Redis is Using a Private Link check_redis_cache_value "Private Link" "${redis_name}" "${res_group}" "properties.privateEndpointConnections" "eq" "Approved" "privateEndpointConnections[0].privateLinkServiceConnectionState.status" # 2.9 Ensure 'Access Keys Authentication' is set to 'Disabled' check_redis_cache_value "Access Keys Authentication" "${redis_name}" "${res_group}" "properties.auth.type" "eq" "Microsoft.KeyVault" "--auth-type" # 2.10 Ensure 'Update Channel' is set to 'Stable' check_redis_cache_value "Update Channel" "${redis_name}" "${res_group}" "updateChannel" "eq" "Stable" "updateChannel" done command="az redisenterprise list --query \"[].name\" --output tsv" command_message "${command}" redis_names=$( eval "${command}" ) if [ -z "${redis_names}" ]; then info_message "No Redis Enterprise instances found" return fi for redis_name in ${redis_names}; do command="az redis enterprise show --name \"${redis_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 2.8 Ensure that Azure Cache for Redis is Using Customer-Managed Keys check_redis_enterprise_cache_value "Customer-Managed Keys" "${redis_name}" "${res_group}" "properties.encryption.customerManagedKeyEncryptionEnabled" "eq" "true" "--customer-managed-key-encryption-enabled" check_redis_enterprise_cache_value "Customer-Managed Keys URL" "${redis_name}" "${res_group}" "properties.encryption.customerManagedKeyEncryptionKeyUrl" "ne" "" "" done } ================================================ FILE: modules/azure/database/audit_azure_sql_db.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_sql_db # # Check Azure SQL Database # # Azure SQL Database # 9.1 Ensure that 'Auditing' is set to 'On' - TBD # 9.2 Ensure that 'Public Network Access' is set to 'Disable' - TBD # 9.3 Ensure no Azure SQL Database firewall rule is overly permissive - TBD # 9.4 Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key - TBD # 9.5 Ensure that Microsoft Entra authentication is Configured for SQL Servers - TBD # 9.6 Ensure that 'Data encryption' is set to 'On' on a SQL Database - TBD # 9.7 Ensure that 'Auditing' Retention is 'greater than 90 days' - TBD # 9.8 Ensure 'Minimum TLS Version' is set to 'TLS 1.2' or higher - TBD # # Refer to Section(s) 9 Page(s) 141-170 Microsoft Azure Database Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_sql_db () { print_function "audit_azure_sql_db" check_message "Azure SQL Database" command="az sql server list --query \"[].name\" --output tsv" command_message "${command}" sql_servers=$( eval "${command}" ) if [ "${sql_servers}" = "" ]; then info_message "No SQL servers found" "info" else for sql_server in ${sql_servers}; do command="az sql server show --name ${sql_server} --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 9.1 Ensure that 'Auditing' is set to 'On' - TBD check_sql_db_value "Auditing" "server" "${sql_server}" "${res_group}" "" "keyVaultKeyUri" "ne" "" "" "" # 9.2 Ensure that 'Public Network Access' is set to 'Disable' - TBD # check_sql_db_value "Microsoft Entra Authentication" "server" "${sql_server}" "${res_group}" "" "" "" "" "" "" # 9.3 Ensure no Azure SQL Database firewall rule is overly permissive - TBD check_sql_db_value "Public Network Access" "server" "${sql_server}" "${res_group}" "" "publicNetworkAccess" "eq" "Disabled" "" "" # 9.4 Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key - TBD check_sql_db_value "Private Endpoints" "server" "${sql_server}" "${res_group}" "" "privateEndpointConnections" "ne" "" "" "" # 9.5 Ensure that Microsoft Entra authentication is Configured for SQL Servers - TBD # check_sql_db_value "Audit Log" "server" "${sql_server}" "${res_group}" "" "audit_log_enabled" "eq" "ON" "" "" # 9.6 Ensure that 'Data encryption' is set to 'On' on a SQL Database - TBD # check_sql_db_value "Audit Log Events" "server" "${sql_server}" "${res_group}" "" "audit_log_events" "eq" "CONNECTION" "" "" # 9.7 Ensure that 'Auditing' Retention is 'greater than 90 days' - TBD # check_sql_db_value "Error Server Log File" "server" "${sql_server}" "${res_group}" "" "error_server_log_file" "eq" "Enabled" "" "" # 9.8 Ensure 'Minimum TLS Version' is set to 'TLS 1.2' or higher - TBD # check_sql_db_value "Require Secure Transport" "server" "${sql_server}" "${res_group}" "" "require_secure_transport" "eq" "ON" "" "" done fi } ================================================ FILE: modules/azure/logging/audit_azure_activity_log_alerts.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_activity_log_alerts # # Check Azure Activity Log Alerts # # 6.1.2.1 Ensure that Activity Log Alert for Create Policy Assignment is enabled # 6.1.2.2 Ensure that Activity Log Alert for Delete Policy Assignment is enabled # 6.1.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group # 6.1.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group # 6.1.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution # 6.1.2.6 Ensure that Activity Log Alert exists for Delete Security Solution # 6.1.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule # 6.1.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule # 6.1.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule # 6.1.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule # 6.1.2.11 Ensure that Activity Log Alert exists for Service Health # Refer to Section(s) 6.1.2.1 Page(s) 227-30 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.2 Page(s) 231-34 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.3 Page(s) 235-38 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.4 Page(s) 239-42 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.5 Page(s) 243-46 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.6 Page(s) 247-50 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.7 Page(s) 251-54 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.8 Page(s) 255-58 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.9 Page(s) 259-62 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.10 Page(s) 263-66 CIS Microsoft Azure Foundations Benchmark v5.0.0 # Refer to Section(s) 6.1.2.11 Page(s) 267-70 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_activity_log_alerts () { print_function "audit_azure_activity_log_alerts" check_message "Azure Activity Log Alerts" command="az account show --query id --output tsv" command_message "${command}" sub_ids="$( eval "${command}" )" for sub_id in ${sub_ids}; do # 6.1.2.1 Ensure that Activity Log Alert for Create Policy Assignment is enabled check_azure_activity_log_alert_value "Create Policy Assignment" "${sub_id}" "Microsoft.Authorization/policyAssignments/write" # 6.1.2.2 Ensure that Activity Log Alert for Delete Policy Assignment is enabled check_azure_activity_log_alert_value "Delete Policy Assignment" "${sub_id}" "Microsoft.Authorization/policyAssignments/delete" # 6.1.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group check_azure_activity_log_alert_value "Create or Update Network Security Group" "${sub_id}" "Microsoft.Network/networkSecurityGroups/write" # 6.1.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group check_azure_activity_log_alert_value "Delete Network Security Group" "${sub_id}" "Microsoft.Network/networkSecurityGroups/delete" # 6.1.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution check_azure_activity_log_alert_value "Create or Update Security Solution" "${sub_id}" "Microsoft.Security/securitySolutions/write" # 6.1.2.6 Ensure that Activity Log Alert exists for Delete Security Solution check_azure_activity_log_alert_value "Delete Security Solution" "${sub_id}" "Microsoft.Security/securitySolutions/delete" # 6.1.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule check_azure_activity_log_alert_value "Create or Update SQL Server Firewall Rule" "${sub_id}" "Microsoft.Sql/servers/firewallRules/write" # 6.1.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule check_azure_activity_log_alert_value "Delete SQL Server Firewall Rule" "${sub_id}" "Microsoft.Sql/servers/firewallRules/delete" # 6.1.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule check_azure_activity_log_alert_value "Create or Update Public IP Address rule" "${sub_id}" "Microsoft.Network/publicIPAddresses/write" # 6.1.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule check_azure_activity_log_alert_value "Delete Public IP Address rule" "${sub_id}" "Microsoft.Network/publicIPAddresses/delete" # 6.1.2.11 Ensure that Activity Log Alert exists for Service Health check_azure_activity_log_alert_value "Service Health" "${sub_id}" "ServiceHealth" done } ================================================ FILE: modules/azure/logging/audit_azure_activity_logs_cmk.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_activity_logs_cmk # # Check Azure Activity Logs CMK # # 6.1.1.3 Ensure that storage account is encrypted with customer-managed key # # Refer to Section(s) 6.1.1.3 Page(s) 203-6 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_activity_logs_cmk () { print_function "audit_azure_activity_logs_cmk" check_message "Azure Activity Logs CMK" command="az account list --query \"[].id\" --output tsv 2>/dev/null" command_message "${command}" sub_ids=$( eval "${command}" ) for sub_id in ${sub_ids}; do command="az monitor diagnostic-settings subscription list --subscription ${sub_id} --query 'value[*].storageAccountId' --output tsv" command_message "${command}" s_accounts=$( eval "${command}" 2> /dev/null ) if [ -z "${s_accounts}" ]; then info_message "No Storage Accounts found" continue fi for s_account in ${s_accounts}; do command="az storage account show --name ${s_account} --query 'encryption.keySource' --output tsv 2>/dev/null" command_message "${command}" key_source=$( eval "${command}" ) command="az storage account show --name ${s_account} --query 'encryption.keyVaultProperties' --output tsv 2>/dev/null" command_message "${command}" key_vault=$( eval "${command}" ) if [ "${key_source}" = "Microsoft.Keyvault" ]; then if [ ! -z "${key_vault}" ] && [ ! "${key_vault}" = "null" ]; then inc_secure "Storage account ${s_account} is encrypted with customer-managed key" else inc_insecure "Storage account ${s_account} is encrypted with customer-managed key but no key vault is specified" fi else inc_insecure "Storage account ${s_account} is not encrypted with customer-managed key" fi done done } ================================================ FILE: modules/azure/logging/audit_azure_application_insights.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_application_insights # # Check Azure Application Insights # # 6.1.3.1 Ensure that Application Insights is enabled # # Refer to Section(s) 6.1.3.1 Page(s) 272-74 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_application_insights () { print_function "audit_azure_application_insights" verbose_message "Azure Application Insights" "check" command="az monitor app-insights component show --query \"[].{ID:appId, Name:name, Tenant:tenantId, Location:location, Provisioning_State:provisioningState}\"" command_message "${command}" insights_check=$( eval "${command}" ) if [ -z "${insights_check}" ]; then inc_secure "Application Insights is enabled" else inc_insecure "Application Insights is not enabled" fi } ================================================ FILE: modules/azure/logging/audit_azure_diagnostic_setting_categories.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_diagnostic_setting_categories # # Check Azure Diagnostic Setting Categories # # 6.1.1.2 Ensure Diagnostic Setting captures appropriate categories # # Refer to Section(s) 6.1.1.2 Page(s) 199-202 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_diagnostic_setting_categories () { print_function "audit_azure_diagnostic_setting_categories" check_message "Azure Diagnostic Setting Categories" command="az account list --query \"[].id\" --output tsv 2>/dev/null" command_message "${command}" sub_ids=$( eval "${command}" ) for sub_id in ${sub_ids}; do for setting in Administrative Alert Policy Security; do command="az monitor diagnostic-settings subscription list --subscription ${sub_id} | grep \"${setting}\" | grep -i \"enabled\" | grep true" command_message "${command}" settings=$( eval "${command}" ) if [ -z "${settings}" ]; then inc_insecure "There is no diagnostic setting for ${setting} for subscription ${sub_id}" else inc_secure "There is a diagnostic setting for ${setting} for subscription ${sub_id}" fi done done } ================================================ FILE: modules/azure/logging/audit_azure_entra_diagnostic_settings.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_entra_diagnostic_settings # # Check Azure Entra Diagnostic Settings # # 6.1.1.9 Ensure that a Microsoft Entra diagnostic setting exists to send Microsoft Entra activity logs to an appropriate destination # # Refer to Section(s) 6.1.1.9 Page(s) 220-2 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_entra_diagnostic_settings () { print_function "audit_azure_entra_diagnostic_settings" check_message "Azure Entra Diagnostic Settings" } ================================================ FILE: modules/azure/logging/audit_azure_graph_diagnostic_settings.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_graph_diagnostic_settings # # Check Azure Graph Diagnostic Settings # # 6.1.1.8 Ensure that a Microsoft Graph diagnostic setting exists to send Microsoft Graph activity logs to an appropriate destination # # Refer to Section(s) 6.1.1.8 Page(s) 218-9 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_graph_diagnostic_settings () { print_function "audit_azure_graph_diagnostic_settings" check_message "Azure Graph Diagnostic Settings" } ================================================ FILE: modules/azure/logging/audit_azure_intune_logs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_intune_logs # # Check Azure Intune Logs # # 6.1.1.10 Ensure that a Microsoft Intune diagnostic setting exists to send Microsoft Intune activity logs to an appropriate destination # # Refer to Section(s) 6.1.1.10 Page(s) 223-5 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_intune_logs () { print_function "audit_azure_intune_logs" check_message "Azure Intune Logs" } ================================================ FILE: modules/azure/logging/audit_azure_logging_and_monitoring.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_logging_and_monitoring # # Check Azure Logging and Monitoring # # 6.1.1.1 Ensure that a 'Diagnostic Setting' exists for Subscription Activity Logs # 6.1.1.2 Ensure Diagnostic Setting captures appropriate categories # 6.1.1.3 Ensure the storage account containing the container with activity logs is encrypted with customer-managed key (CMK) # 6.1.1.4 Ensure that logging for Azure Key Vault is 'Enabled' # 6.1.1.5 Ensure that Network Security Group Flow logs are captured and sent to Log Analytics - TBD # 6.1.1.6 Ensure that logging for Azure AppService 'HTTP logs' is enabled - TBD # 6.1.1.7 Ensure that virtual network flow logs are captured and sent to Log Analytics # 6.1.1.8 Ensure that a Microsoft Entra diagnostic setting exists to send Microsoft Graph activity logs to an appropriate destination # 6.1.1.9 Ensure that a Microsoft Entra diagnostic setting exists to send Microsoft Entra activity logs to an appropriate destination # 6.1.1.10 Ensure that Intune logs are captured and sent to Log Analytics # 6.1.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment # 6.1.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment # 6.1.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group # 6.1.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group # 6.1.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution # 6.1.2.6 Ensure that Activity Log Alert exists for Delete Security # 6.1.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule # 6.1.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule # 6.1.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule # 6.1.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule # 6.1.2.11 Ensure that an Activity Log Alert exists for Service Health # 6.1.3.1 Ensure Application Insights are Configured # 6.1.4 Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it # 6.1.5 Ensure that SKU Basic/Consumption is not used on artifacts that need to be monitored (Particularly for Production Workloads) # # Refer to Section(s) 6.1-2 Page(s) 191-286 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_logging_and_monitoring () { print_function "audit_azure_logging_and_monitoring" check_message "Azure Logging and Monitoring" # 6.1.1.1 Ensure that a 'Diagnostic Setting' exists for Subscription Activity Logs audit_azure_subscription_diagnostic_settings # 6.1.1.2 Ensure Diagnostic Setting captures appropriate categories audit_azure_diagnostic_setting_categories # 6.1.1.3 Ensure the storage account containing the container with activity logs is encrypted with customer-managed key (CMK) audit_azure_activity_logs_cmk # 6.1.1.4 Ensure that logging for Azure Key Vault is 'Enabled' audit_azure_key_vault_logging # 6.1.1.5 Ensure that Network Security Group Flow logs are captured and sent to Log Analytics - TBD audit_azure_nsg_flow_logs # 6.1.1.6 Ensure that logging for Azure AppService 'HTTP logs' is enabled - TBD audit_azure_app_service_http_logs # 6.1.1.7 Ensure that virtual network flow logs are captured and sent to Log Analytics audit_azure_virtual_network_flow_logs # 6.1.1.8 Ensure that a Microsoft Entra diagnostic setting exists to send Microsoft Graph activity logs to an appropriate destination audit_azure_graph_diagnostic_settings # 6.1.1.9 Ensure that a Microsoft Entra diagnostic setting exists to send Microsoft Entra activity logs to an appropriate destination audit_azure_entra_diagnostic_settings # 6.1.1.10 Ensure that Intune logs are captured and sent to Log Analytics audit_azure_intune_logs # 6.1.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment # 6.1.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment # 6.1.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group # 6.1.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group # 6.1.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution # 6.1.2.6 Ensure that Activity Log Alert exists for Delete Security # 6.1.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule # 6.1.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule # 6.1.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule # 6.1.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule # 6.1.2.11 Ensure that an Activity Log Alert exists for Service Health audit_azure_activity_log_alerts # 6.1.3.1 Ensure Application Insights are Configured audit_azure_application_insights # 6.1.4 Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it audit_azure_resource_logging # 6.1.5 Ensure that SKU Basic/Consumption is not used on artifacts that need to be monitored (Particularly for Production Workloads) audit_azure_sku_basic_consumption } ================================================ FILE: modules/azure/logging/audit_azure_resource_logging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_resource_logging # # Check Azure Resource Logging # # 6.1.4 Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it # # Refer to Section(s) 6.1.4 Page(s) 275-80 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_resource_logging () { print_function "audit_azure_resource_logging" check_message "Azure Resource Logging" command="az account show --query id --output tsv" command_message "${command}" sub_ids="$( eval "${command}" )" for sub_id in $sub_ids; do command="az resource list --subscription \"${sub_id}\" --query \"[].id\" --output tsv" command_message "${command}" res_ids="$( eval "${command}" )" for res_id in ${res_ids}; do check_azure_monitoring_diagnostics_value "${res_id}" done done } ================================================ FILE: modules/azure/logging/audit_azure_subscription_diagnostic_settings.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_subscription_diagnostic_settings # # Check Azure Subscription Diagnostic Settings # # 6.1.1.1 Ensure that Diagnostic Settings are enabled for all Azure Subscriptions # # Refer to Section(s) 6.1.1.1 Page(s) 194-8 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_subscription_diagnostic_settings () { print_function "audit_azure_subscription_diagnostic_settings" check_message "Azure Subscription Diagnostic Settings Activity Logs" command="az account list --query \"[].id\" --output tsv 2>/dev/null" command_message "${command}" sub_ids=$( eval "${command}" ) for sub_id in ${sub_ids}; do command="az monitor diagnostic-settings list --scope /subscriptions/${sub_id} --query \"[].value\" --output tsv 2>/dev/null" command_message "${command}" settings=$( eval "${command}" ) if [ -z "${settings}" ]; then inc_insecure "There are no diagnostic settings for subscription ${sub_id}" else inc_secure "There are diagnostic settings for subscription ${sub_id}" fi command="az resource list --subscription ${sub_id} --query \"[].id\" --output tsv" command_message "${command}" res_ids=$( eval "${command}" ) for res_id in ${res_ids}; do command="az monitor diagnostic-settings list --resource ${res_id} --query \"[].value\" --output tsv 2>/dev/null" command_message "${command}" settings=$( eval "${command}" ) if [ -z "${settings}" ]; then inc_insecure "There are no diagnostic settings for resource ${res_id}" else inc_secure "There are diagnostic settings for resource ${res_id}" fi done done } ================================================ FILE: modules/azure/main/audit_azure_custom_subscription_admin_roles.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_custom_subscription_admin_roles # # Check Azure Custom Subscription Admin Roles # # 5.23 Ensure that custom subscription administrator roles are not used # # Refer to Section(s) 5.23 Page(s) 174-6 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_custom_subscription_admin_roles () { print_function "audit_azure_custom_subscription_admin_roles" check_message "Azure Custom Subscription Admin Roles" command="az role definition list --custom-role-only True | grep -iE \"assignableScope|subscription\" | grep \"*\"" command_message "${command}" actual_value=$( eval "${command}" ) if [ -z "${actual_value}" ]; then inc_secure "No custom subscription administrator roles exist" else inc_insecure "Custom subscription administrator roles exist" verbose_message "az role definition delete --name " fi } ================================================ FILE: modules/azure/main/audit_azure_extensions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_extensions # # Audit Azure extensions setting # # Make sure extenstions are not set to auto install and are not set to preview versions # # Refer to https://learn.microsoft.com/en-us/cli/azure/azure-cli-extensions-overview?view=azure-cli-latest # # This requires the Azure CLI to be installed and configured #. audit_azure_extensions () { print_function "audit_azure_extensions" check_message "Azure extensions settings" for parameter_name in "extension.use_dynamic_install" "extension.run_after_dynamic_install" "extension.dynamic_install_allow_preview"; do if [ "${parameter_name}" = "extension.dynamic_install_allow_preview" ]; then correct_value="false" else correct_value="no" fi check_message "Azure extensions parameter \"${parameter_name}\" is set to \"${correct_value}\"" command="az config get \"${parameter_name}\" --query value --output tsv 2> /dev/null" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "${correct_value}" ]; then inc_secure "Azure extensions parameter \"${parameter_name}\" is set to \"${correct_value}\"" else inc_insecure "Azure extensions parameter \"${parameter_name}\" is not set to \"${correct_value}\"" verbose_message "az config set ${parameter_name}=${correct_value}" "fix" fi done } ================================================ FILE: modules/azure/main/audit_azure_sku_basic_consumption.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_sku_basic_consumption # # Check Azure SKU Basic/Consumption # # 6.1.5 Ensure that SKU Basic/Consumption is not used on artifacts that need to be monitored (Particularly for Production Workloads) # # Refer to Section(s) 6.1.5 Page(s) 281-3 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_sku_basic_consumption () { print_function "audit_azure_sku_basic_consumption" check_message "Azure SKU Basic/Consumption" command="az graph query -q \"Resources | where sku contains 'Basic' or sku contains 'consumption' | order by type\" --query count --output tsv 2> /dev/null" command_message "${command}" res_check="$( eval "${command}" )" if [ "${res_check}" -eq 0 ]; then inc_secure "No resources that are being monitored are using SKU Basic/Consumption" else inc_insecure "Resources that are being monitored are using SKU Basic/Consumption" fi } ================================================ FILE: modules/azure/main/audit_azure_subscription_owners.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_subscription_owners # # Check Azure Subscription Owners # # 5.27 Ensure that there are no more than 3 members with the Subscription Owner role # # Refer to Section(s) 5.27 Page(s) 186-8 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_subscription_owners () { print_function "audit_azure_subscription_owners" check_message "Azure Subscription Owners" command="az account list --query \"[].id\" --output tsv" command_message "${command}" sub_ids=$( eval "${command}" ) max_owners="3" for sub_id in ${sub_ids}; do command="az role assignment list --role Owner --scope /subscriptions/${sub_id} --query \"[].id\" --output tsv" command_message "${command}" role_owners=$( eval "${command}" ) if [ -z "${role_owners}" ]; then inc_secure "There are members with the Subscription Owner role" else owner_count=$( echo "${role_owners}" | wc -l ) if [ "${owner_count}" -gt "${max_owners}" ]; then inc_insecure "There are more than ${max_owners} members with the Subscription Owner role" else inc_secure "There are ${owner_count} members with the Subscription Owner role" fi role_assignment_ids=$( echo "${role_owners}" | tr '\n' ' ' ) fix_message "az role assignment delete --ids \"${role_assignment_ids}\"" fi done } ================================================ FILE: modules/azure/main/audit_azure_survey.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_survey # # Audit Azure survey setting # # Refer to https://learn.microsoft.com/en-au/cli/azure/command-line-tools-survey-guidance?view=azure-cli-latest # # This requires the Azure CLI to be installed and configured #. audit_azure_survey () { print_function "audit_azure_survey" check_message "Azure survey setting" command="az config get core.survey_message --query value --output tsv 2> /dev/null" command_message "${command}" survey=$( eval "${command}" ) if [ "${survey}" = "false" ]; then inc_secure "Azure survey reminder is disabled" else inc_insecure "Azure survey reminder is enabled" verbose_message "az config set core.survey_message=false" "fix" fi } ================================================ FILE: modules/azure/network/audit_azure_network_private_endpoints.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_network_private_endpoints # # Check Azure Network Private Endpoints # # 2.2.2.1 Ensure Private Endpoints are used to access {service} # # Refer to Section(s) 2 Page(s) 25- CIS Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_network_private_endpoints () { print_function "audit_azure_network_private_endpoints" check_message "Azure Network Private Endpoints" command="az network private-endpoint list --query \"[].id\" --output tsv" command_message "${command}" p_endpoints=$( eval "${command}" 2> /dev/null ) if [ -z "${p_endpoints}" ]; then info_message "No Private Endpoints found" return fi for p_endpoint in ${p_endpoints}; do command="az network private-endpoint show --id \"${p_endpoint}\" --query \"id\" --output tsv" command_message "${command}" res_name=$( eval "${command}" ) command="az network private-endpoint show --id \"${p_endpoint}\" --query \"name\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 2.2.2.1 Ensure Private Endpoints are used to access {service} command="az network private-endpoint list --resource-group \"${res_group}\" --query \"[?contains(resourceGroup, '${res_group}') && contains(name, '${res_name}')]\" --output tsv" command_message "${command}" p_end_test=$( eval "${command}" ) if [ -z "${p_end_test}" ]; then inc_insecure "Private Endpoints are not used to access ${res_name}" else inc_secure "Private Endpoints are used to access ${res_name}" fi done } ================================================ FILE: modules/azure/network/audit_azure_network_security_perimeter.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_network_security_perimeter # # Check Azure Network Security Perimeter # # 7.16 Ensure Azure Network Security Perimeter is used to secure Azure platform-as-a-service resources # # Refer to Section(s) 7.16 Page(s) 334-7 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_network_security_perimeter () { print_function "audit_azure_network_security_perimeter" check_message "Azure Network Security Perimeter" command="az group list --query '[].name' --output tsv 2> /dev/null" command_message "${command}" group_names=$( eval "${command}" ) if [ -z "${group_names}" ]; then info_message "No NSP instances found" return fi for group_name in ${group_names}; do command="az network perimeter list --resource-group \"${group_name}\" --query '[].name' --output tsv 2> /dev/null" command_message "${command}" nsp_list=$( eval "${command}" ) if [ -z "${nsp_list}" ]; then inc_insecure "No Azure Network Security Perimeter found for resource group \"${group_name}\"" else for nsp_name in ${nsp_list}; do check_azure_network_security_perimeter_value "${nsp_name}" "${group_name}" "association" "[].resourceGroup" "eq" "${group_name}" done fi done } ================================================ FILE: modules/azure/network/audit_azure_network_watcher.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_network_watcher # # Check Azure Network Watcher # # 7.6 Ensure that Network Watcher is 'Enabled' for Azure Regions that are in use # # Refer to Section(s) 7.6 Page(s) 306-8 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_network_watcher () { print_function "audit_azure_network_watcher" check_message "Azure Network Watcher" command="az network watcher list --query '[].id' --output tsv 2> /dev/null" command_message "${command}" watcher_ids=$( eval "${command}" ) if [ -z "${watcher_ids}" ]; then info_message "No Network Watcher instances found" return fi for watcher_id in ${watcher_ids}; do check_azure_network_watcher_value "${watcher_id}" "provisioningState" "Succeeded" done } ================================================ FILE: modules/azure/network/audit_azure_network_watcher_flow_logs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_network_watcher_flow_logs # # Check Azure Network Watcher Flow Logs # # 7.8 Ensure that virtual network flow log retention days is set to greater than or equal to 90 # # Refer to Section(s) 7.8 Page(s) 311-3 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_network_watcher_flow_logs () { print_function "audit_azure_network_watcher_flow_logs" check_message "Azure Network Watcher Flow Logs" command="az network watcher list --query '[].location' --output tsv 2> /dev/null" command_message "${command}" locations=$( eval "${command}" ) if [ -z "${locations}" ]; then info_message "No Network Watcher instances found" return fi for location in $locations; do command="az network watcher list-flow-logs --location \"${location}\" --query '[].name' --output tsv 2> /dev/null" command_message "${command}" flow_logs=$( eval "${command}" ) if [ -z "${flow_logs}" ]; then info_message "No Flow Logs found" return fi for flow_log in ${flow_logs}; do check_azure_network_watcher_flow_logs_value "${location}" "${flow_log}" "retentionPolicy.days" "90" "retention" done done } ================================================ FILE: modules/azure/network/audit_azure_networking_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_networking_services # # Audit Azure Networking Services # # 7.1 Ensure that RDP access from the Internet is evaluated and restricted # 7.2 Ensure that SSH access from the Internet is evaluated and restricted # 7.3 Ensure that UDP access from the Internet is evaluated and restricted # 7.4 Ensure that HTTP(S) access from the Internet is evaluated and restricted # 7.5 Ensure that network security group flow log retention days is set to greater than or equal to 90 # 7.6 Ensure that Network Watcher is 'Enabled' for Azure Regions that are in use # 7.7 Ensure that Public IP addresses are Evaluated on a Periodic Basis (Manual) # 7.8 Ensure that virtual network flow log retention days is set to greater than or equal to 90 # 7.9 Ensure 'Authentication type' is set to 'Azure Active Directory' only for Azure VPN Gateway point-to-site configuration - TBD # 7.10 Ensure Azure Web Application Firewall (WAF) is enabled on Azure Application Gateway # 7.11 Ensure subnets are associated with network security groups # 7.12 Ensure the SSL policy's 'Min protocol version' is set to 'TLSv1_2' or higher on Azure Application Gateway # 7.13 Ensure 'HTTP2' is set to 'Enabled' on Azure Application Gateway # 7.14 Ensure request body inspection is enabled in Azure Web Application Firewall policy on Azure Application Gateway # 7.15 Ensure bot protection is enabled in Azure Web Application Firewall policy on Azure Application Gateway # 7.16 Ensure Azure Network Security Perimeter is used to secure Azure platform-as-a-service resources # # Refer to Section(s) 7.1-16 Page(s) 287-337 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_networking_services () { print_function "audit_azure_networking_services" check_message "Azure Networking Services" audit_azure_nsg_security_rules audit_azure_network_watcher audit_azure_public_ips audit_azure_network_watcher_flow_logs audit_azure_authentication_type } ================================================ FILE: modules/azure/network/audit_azure_public_ips.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_public_ips # # Audit Azure Public IPs # # 7.7 Ensure that Public IP addresses are Evaluated on a Periodic Basis (Manual) # # Refer to Section(s) 7.7 Page(s) 309-10 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_public_ips () { print_function "audit_azure_public_ips" check_message "Azure Public IPs" command="az network public-ip list --query '[].id' --output tsv" command_message "${command}" res_ids=$( eval "${command}" ) if [ -z "${res_ids}" ]; then info_message "No Public IPs found" return fi for res_id in ${res_ids}; do check_azure_public_ip_value "${res_id}" "ipAddress" "eq" "" done } ================================================ FILE: modules/azure/network/audit_azure_virtual_network_flow_logs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_virtual_network_flow_logs # # Check Azure Virtual Network Flow Logs # # 6.1.1.7 Ensure that virtual network flow logs are captured and sent to Log Analytics # # Refer to Section(s) 6.1.1.7 Page(s) 215-7 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_virtual_network_flow_logs () { print_function "audit_azure_virtual_network_flow_logs" check_message "Azure Virtual Network Flow Logs" } ================================================ FILE: modules/azure/network/audit_azure_vnets.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_vnets # # Check Azure VNets # # 7.11 Ensure subnets are associated with network security groups # # Refer to Section(s) 7.11 Page(s) 319-21 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_vnets () { print_function "audit_azure_vnets" check_message "Azure VNets" command="az network vnet list --query '[].resourceGroup' --output tsv 2> /dev/null" command_message "${command}" res_groups=$( eval "${command}" ) if [ -z "${res_groups}" ]; then info_message "No VNets found" return fi for res_group in $res_groups; do command="az network vnet list --resource-group \"${res_group}\" --query '[].name' --output tsv 2> /dev/null" command_message "${command}" vnet_list=$( eval "${command}" ) for vnet_name in $vnet_list; do command="az network vnet show --name \"${vnet_name}\" --resource-group \"${res_group}\" --query 'subnets[].name' --output tsv 2> /dev/null" command_message "${command}" subnet_list=$( eval "${command}" ) for subnet_name in ${subnet_list}; do check_azure_vnet_value "${vnet_name}" "${res_group}" "${subnet_name}" "networkSecurityGroup.id" "ne" "" done done done } ================================================ FILE: modules/azure/security/audit_azure_authentication_type.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_authentication_type # # Check Azure Authentication Type # # 7.9 Ensure 'Authentication type' is set to 'Azure Active Directory' only for Azure VPN Gateway point-to-site configuration # # Refer to Section 7.9 Page(s) 315-8 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_authentication_type () { print_function "audit_azure_authentication_type" check_message "Azure Authentication Type" } ================================================ FILE: modules/azure/security/audit_azure_guest_users.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_guest_users # # Check Azure Guest Users # # 5.3.2 Ensure that guest user access is restricted # # Refer to Section(s) 5.3.2 Page(s) 111-4 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_guest_users () { print_function "audit_azure_guest_users" check_message "Azure Guest Users" command="az ad user list --query \"[?contains(userType, 'Guest')]\" --query \"id\" --output tsv" command_message "${command}" guest_users=$( eval "${command}" ) if [ -z "${guest_users}" ]; then inc_secure "No guest users found" else inc_insecure "Guest users found: ${guest_users}" fi } ================================================ FILE: modules/azure/security/audit_azure_identity_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_identity_services # # Check Azure Identity Services # # 5.1.1 Ensure that 'security defaults' is enabled in Microsoft Entra ID - TBD # 5.1.2 Ensure that 'multifactor authentication' is 'enabled' for all users - TBD # 5.1.3 Ensure that 'Allow users to remember multifactor authentication on devices they trust' is disabled - TBD # 5.2.1 Ensure that 'trusted locations' are defined - TBD # 5.2.2 Ensure that an exclusionary geographic Conditional Access policy is considered - TBD # 5.2.3 Ensure that an exclusionary device code flow policy is considered - TBD # 5.2.4 Ensure that a multifactor authentication policy exists for all users - TBD # 5.2.5 Ensure that multifactor authentication is required for risky sign-ins - TBD # 5.2.6 Ensure that multifactor authentication is required for Windows Azure Service Management API - TBD # 5.2.7 Ensure that multifactor authentication is required to access Microsoft Admin Portals - TBD # 5.2.8 Ensure a Token Protection Conditional Access policy is considered - TBD # 5.3.1 Ensure that Azure admin accounts are not used for daily operations - TBD # 5.3.2 Ensure that guest users are reviewed on a regular basis # 5.3.3 Ensure that use of the 'User Access Administrator' role is restricted # 5.3.4 Ensure that all 'privileged' role assignments are periodically reviewed - TBD # 5.3.5 Ensure disabled user accounts do not have read, write, or owner permissions - TBD # 5.3.6 Ensure 'Tenant Creator' role assignments are periodically reviewed - TBD # 5.3.7 Ensure all non-privileged role assignments are periodically reviewed - TBD # 5.4 Ensure that 'Restrict non-admin users from creating tenants' is set to 'Yes' - TBD # 5.5 Ensure that 'Number of methods required to reset' is set to '2' - TBD # 5.6 Ensure that account 'Lockout threshold' is less than or equal to '10' - TBD # 5.7 Ensure that account 'Lockout duration in seconds' is greater than or equal to '60' - TBD # 5.8 Ensure that a 'Custom banned password list' is set to 'Enforce' - TBD # 5.9 Ensure that 'Number of days before users are asked to re-confirm their authentication information' is not set to '0' - TBD # 5.10 Ensure that 'Notify users on password resets?' is set to 'Yes' - TBD # 5.11 Ensure that 'Notify all admins when other admins reset their password?' is set to 'Yes' - TBD # 5.12 Ensure that 'User consent for applications' is set to 'Do not allow user consent' # 5.13 Ensure that 'User consent for applications' is set to 'Allow user consent for apps from verified publishers, for selected permissions' - TBD # 5.14 Ensure that 'Users can register applications' is set to 'No' - TBD # 5.15 Ensure that 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects' - TBD # 5.16 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles [...]' or 'No one [..]' - TBD # 5.18 Ensure that 'Restrict user ability to access groups features in My Groups' is set to 'Yes' - TBD # 5.19 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No' - TBD # 5.20 Ensure that 'Owners can manage group membership requests in My Groups' is set to 'No' - TBD # 5.21 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No' - TBD # 5.22 Ensure that 'Require Multifactor Authentication to register or join devices with Microsoft Entra' is set to 'Yes' - TBD # 5.23 Ensure that no custom subscription administrator roles exist # 5.24 Ensure that a custom role is assigned permissions for administering resource locks - TBD # 5.25 Ensure that 'Subscription leaving Microsoft Entra tenant' and 'Subscription entering Microsoft Entra tenant' is set to 'Permit no one' - TBD # 5.26 Ensure fewer than 5 users have global administrator assignment - TBD # 5.27 Ensure there are between 2 and 3 subscription owners # 5.28 Ensure passwordless authentication methods are considered - TBD # # Refer to Section(s) 5.1-28 Page(s) 70-190 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_identity_services () { print_function "audit_azure_identity_services" check_message "Azure Identity Services" # 5.1.1 Ensure that 'security defaults' is enabled in Microsoft Entra ID - TBD # 5.1.2 Ensure that 'multifactor authentication' is 'enabled' for all users - TBD # 5.1.3 Ensure that 'Allow users to remember multifactor authentication on devices they trust' is disabled - TBD # 5.2.1 Ensure that 'trusted locations' are defined - TBD # 5.2.2 Ensure that an exclusionary geographic Conditional Access policy is considered - TBD # 5.2.3 Ensure that an exclusionary device code flow policy is considered - TBD # 5.2.4 Ensure that a multifactor authentication policy exists for all users - TBD # 5.2.5 Ensure that multifactor authentication is required for risky sign-ins - TBD # 5.2.6 Ensure that multifactor authentication is required for Windows Azure Service Management API - TBD # 5.2.7 Ensure that multifactor authentication is required to access Microsoft Admin Portals - TBD # 5.2.8 Ensure a Token Protection Conditional Access policy is considered - TBD # 5.3.1 Ensure that Azure admin accounts are not used for daily operations - TBD # 5.3.2 Ensure that guest users are reviewed on a regular basis audit_azure_guest_users # 5.3.3 Ensure that use of the 'User Access Administrator' role is restricted audit_azure_user_access_admin_role # 5.3.4 Ensure that all 'privileged' role assignments are periodically reviewed - TBD # 5.3.5 Ensure disabled user accounts do not have read, write, or owner permissions - TBD # 5.3.6 Ensure 'Tenant Creator' role assignments are periodically reviewed - TBD # 5.3.7 Ensure all non-privileged role assignments are periodically reviewed - TBD # 5.4 Ensure that 'Restrict non-admin users from creating tenants' is set to 'Yes' - TBD # 5.5 Ensure that 'Number of methods required to reset' is set to '2' - TBD # 5.6 Ensure that account 'Lockout threshold' is less than or equal to '10' - TBD # 5.7 Ensure that account 'Lockout duration in seconds' is greater than or equal to '60' - TBD # 5.8 Ensure that a 'Custom banned password list' is set to 'Enforce' - TBD # 5.9 Ensure that 'Number of days before users are asked to re-confirm their authentication information' is not set to '0' - TBD # 5.10 Ensure that 'Notify users on password resets?' is set to 'Yes' - TBD # 5.11 Ensure that 'Notify all admins when other admins reset their password?' is set to 'Yes' - TBD # 5.12 Ensure that 'User consent for applications' is set to 'Do not allow user consent' # 5.13 Ensure that 'User consent for applications' is set to 'Allow user consent for apps from verified publishers, for selected permissions' - TBD # 5.14 Ensure that 'Users can register applications' is set to 'No' - TBD # 5.15 Ensure that 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects' - TBD # 5.16 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles [...]' or 'No one [..]' - TBD # 5.18 Ensure that 'Restrict user ability to access groups features in My Groups' is set to 'Yes' - TBD # 5.19 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No' - TBD # 5.20 Ensure that 'Owners can manage group membership requests in My Groups' is set to 'No' - TBD # 5.21 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No' - TBD # 5.22 Ensure that 'Require Multifactor Authentication to register or join devices with Microsoft Entra' is set to 'Yes' - TBD # 5.23 Ensure that no custom subscription administrator roles exist audit_azure_custom_subscription_admin_roles # 5.24 Ensure that a custom role is assigned permissions for administering resource locks - TBD # 5.25 Ensure that 'Subscription leaving Microsoft Entra tenant' and 'Subscription entering Microsoft Entra tenant' is set to 'Permit no one' - TBD # 5.26 Ensure fewer than 5 users have global administrator assignment - TBD # 5.27 Ensure there are between 2 and 3 subscription owners audit_azure_subscription_owners # 5.28 Ensure passwordless authentication methods are considered - TBD } ================================================ FILE: modules/azure/security/audit_azure_locks.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_locks # # Audit Azure Locks # # This requires the Azure CLI to be installed and configured # audit_azure_locks () { res_type="${1}" lock_type="${2}" print_function "audit_azure_locks" check_message "Azure Locks with Resource Type ${res_type}" command="az lock list --query \"[].name\" --resource-type \"${res_type}\" --output tsv" command_message "${command}" lock_names=$( eval "${command}" 2> /dev/null ) if [ -z "${lock_names}" ]; then info_message "No Locks found" return fi for lock_name in ${lock_names}; do command="az lock show --name \"${lock_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) check_azure_lock_value "${lock_name}" "${res_group}" "${res_type}" "properties.level" "eq" "${lock_type}" "--lock-type" done } ================================================ FILE: modules/azure/security/audit_azure_microsoft_defender.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_microsoft_defender # # Check Azure Microsoft Defender # # 8.1.1.1 Ensure Microsoft Defender CSPM is set to 'On' # 8.1.2.1 Ensure Microsoft Defender CWP is set to 'On' # 8.1.3.1 Ensure that Defender for Servers is set to 'On' # 8.1.3.2 Ensure that 'Vulnerability assessment for machines' component status is set to 'On' # 8.1.4.1 Ensure That Microsoft Defender for Containers Is Set To 'On' # 8.1.5.1 Ensure That Microsoft Defender for Storage Is Set To 'On' # 8.1.6.1 Ensure That Microsoft Defender for App Services Is Set To 'On' # 8.1.7.1 Ensure That Microsoft Defender for Azure Cosmos DB Is Set To 'On' # 8.1.7.2 Ensure That Microsoft Defender for Open-Source Relational Databases Is Set To 'On' # 8.1.7.3 Ensure That Microsoft Defender for (Managed Instance) Azure SQL Databases Is Set To 'On' # 8.1.7.4 Ensure That Microsoft Defender for SQL Servers on Machines Is Set To 'On' # 8.1.8.1 Ensure That Microsoft Defender for Azure Key Vault Is Set To 'On' # 8.1.9.1 Ensure That Microsoft Defender for Resource Manager Is Set To 'On' # 8.1.10 Ensure that Microsoft Defender for Cloud is configured to check VM operating systems for updates - TBD # 8.1.16 Ensure that Microsoft Defender External Attack Surface Monitoring (EASM) is enabled # 8.2.1 Ensure That Microsoft Defender for IoT Hub Is Set To 'On' # # Refer to Section(s) 8.1.1- Page(s) 338-472 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_microsoft_defender () { print_function "audit_azure_microsoft_defender" check_message "Azure Microsoft Defender" # 8.1.1.1 Ensure Microsoft Defender CSPM is set to 'On' check_azure_microsoft_defender_value "Cloud Security Posture Management (CSPM)" "CloudPosture" "Standard" "On" "" # 8.1.2.1 Ensure Microsoft Defender CWP is set to 'On' check_azure_microsoft_defender_value "Cloud Workload Protection (CWP)" "Api" "Standard" "On" "" # 8.1.3.1 Ensure that Defender for Servers is set to 'On' check_azure_microsoft_defender_value "Defender for Servers" "VirtualMachines" "Standard" "On" "" # 8.1.4.1 Ensure That Microsoft Defender for Containers Is Set To 'On' check_azure_microsoft_defender_value "Defender for Containers" "ContainerRegistry" "Standard" "On" "" # 8.1.5.1 Ensure That Microsoft Defender for Storage Is Set To 'On' check_azure_microsoft_defender_value "Defender for Storage" "StorageAccounts" "Standard" "On" "" # 8.1.6.1 Ensure That Microsoft Defender for App Services Is Set To 'On' check_azure_microsoft_defender_value "Defender for App Services" "AppServices" "Standard" "On" "" # 8.1.7.1 Ensure That Microsoft Defender for Azure Cosmos DB Is Set To 'On' check_azure_microsoft_defender_value "Defender for Cosmos DB" "CosmosDbs" "Standard" "On" "" # 8.1.7.2 Ensure That Microsoft Defender for Open-Source Relational Databases Is Set To 'On' check_azure_microsoft_defender_value "Defender for Open-Source Relational Databases" "OpenSourceRelationalDatabases" "Standard" "On" "" # 8.1.7.3 Ensure That Microsoft Defender for (Managed Instance) Azure SQL Databases Is Set To 'On' check_azure_microsoft_defender_value "Defender for (Managed Instance) Azure SQL Databases" "SqlServers" "Standard" "On" "" # 8.1.7.4 Ensure That Microsoft Defender for SQL Servers on Machines Is Set To 'On' check_azure_microsoft_defender_value "Defender for SQL Servers on Machines" "SqlServersVirtualMachines" "Standard" "On" "" # 8.1.8.1 Ensure That Microsoft Defender for Azure Key Vault Is Set To 'On' check_azure_microsoft_defender_value "Defender for Azure Key Vault" "KeyVaults" "Standard" "On" "" # 8.1.9.1 Ensure That Microsoft Defender for Resource Manager Is Set To 'On' check_azure_microsoft_defender_value "Defender for Resource Manager" "Arm" "Standard" "On" "" # 8.1.10 Ensure that Microsoft Defender for Cloud is configured to check VM operating systems for updates - TBD # 8.1.16 Ensure that Microsoft Defender External Attack Surface Monitoring (EASM) is enabled check_azure_microsoft_defender_value "Defender for External Attack Surface Monitoring" "" "Standard" "Exists" "Microsoft.Easm/workspaces" # 8.2.1 Ensure That Microsoft Defender for IoT Hub Is Set To 'On' # check_azure_microsoft_defender_value "Defender for IoT Hub" "IotHubs" "Standard" "On" "Microsoft.Devices/IotHubs" } ================================================ FILE: modules/azure/security/audit_azure_nsg_flow_logs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_nsg_flow_logs # # Check Azure NSG Flow Logs # # 6.1.1.5 Ensure that Network Security Group Flow logs are captured and sent to Log Analytics # # Refer to Section(s) 6.1.1.5 Page(s) 211-2 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_nsg_flow_logs () { print_function "audit_azure_nsg_flow_logs" check_message "Azure NSG Flow Logs" } ================================================ FILE: modules/azure/security/audit_azure_nsg_security_rules.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_nsg_security_rules # # Check Azure NSG Security Rules # # 7.1 Ensure that RDP access from the Internet is evaluated and restricted # 7.2 Ensure that SSH access from the Internet is evaluated and restricted # 7.3 Ensure that UDP access from the Internet is evaluated and restricted # 7.4 Ensure that HTTP(S) access from the Internet is evaluated and restricted # # Refer to Section(s) 7.1-4 Pages 288-302 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_nsg_security_rules () { print_function "audit_azure_nsg_security_rules" check_message "Azure NSG Security Rules" command="az network nsg list --query \"[].id\" --output tsv 2> /dev/null" command_message "${command}" res_ids=$( eval "${command}" ) if [ -z "${res_ids}" ]; then info_message "No NSG instances found" return fi for res_id in ${res_ids}; do command="az network nsg show --ids ${res_id} --query \"name\" --output tsv 2> /dev/null" command_message "${command}" res_name=$( eval "${command}" ) command="az network nsg show --ids ${res_id} --query \"resourceGroup\" --output tsv 2> /dev/null" command_message "${command}" res_group=$( eval "${command}" ) command="az network nsg rule list --resource-group ${res_group} --nsg-name ${res_name} --query \"[].id\" --output tsv 2> /dev/null" command_message "${command}" rule_ids=$( eval "${command}" ) for rule_id in ${rule_ids}; do for port_no in 3389 22 53 80 123 161 389 443 1900; do service_name=$( get_service_name_from_port_no "${port_no}" ) check_azure_nsg_security_rule_value "${service_name}" "${rule_id}" "Inbound" "access" "ne" "Allow" check_azure_nsg_security_rule_value "${service_name}" "${rule_id}" "Inbound" "destinationPortRange" "ne" "${port_no}" check_azure_nsg_security_rule_value "${service_name}" "${rule_id}" "Inbound" "destinationPortRanges" "ne" "${port_no}" check_azure_nsg_security_rule_value "${service_name}" "${rule_id}" "Inbound" "sourceAddressPrefix" "ne" "0.0.0.0/0" check_azure_nsg_security_rule_value "${service_name}" "${rule_id}" "Inbound" "sourceAddressPrefixes" "ne" "0.0.0.0/0" done done done } ================================================ FILE: modules/azure/security/audit_azure_security_contacts.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_security_contacts # # Check Azure Security Contacts # # 8.1.12 Ensure That 'All users with the following roles' is set to 'Owner' # 8.1.13 Ensure 'Additional email addresses' is Configured with a Security Contact Email # 8.1.14 Ensure that 'Notify about alerts with the following severity (or higher)' is enabled # # Refer to Section(s) 8.1.12 Page(s) 406-8 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # Refer to https://learn.microsoft.com/en-us/cli/azure/security/contact?view=azure-cli-latest # # This requires the Azure CLI to be installed and configured #. audit_azure_security_contacts () { print_function "audit_azure_security_contacts" check_message "Azure Security Contacts" command="az security contact list --query \"[].name\" --output tsv 2> /dev/null" command_message "${command}" c_names=$( eval "${command}" ) if [ -z "${c_names}" ]; then inc_insecure "No Azure Security Contacts found" verbose_message "az security contact create --name --email --notifications-by-role '{\"state\":\"On\",\"roles\":[\"Owner\"]}' --alert-notifications '{\"state\":\"On\",\"minimalSeverity\":\"Low\"}'" "fix" else for c_name in ${c_names}; do check_azure_security_contact_value "${c_name}" "email" "ne" "" check_azure_security_contact_value "${c_name}" "alertNotifications.state" "eq" "On" check_azure_security_contact_value "${c_name}" "notificationsByRole.roles" "eq" "Owner" check_azure_security_contact_value "${c_name}" "alertNotifications.minimalSeverity" "eq" "Low" done fi } ================================================ FILE: modules/azure/security/audit_azure_security_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_security_services # # Check Azure Security Services # # 8.1.1.1 Ensure Microsoft Defender CSPM is set to 'On' # 8.1.2.1 Ensure Microsoft Defender for APIs is set to 'On' # 8.1.3.1 Ensure that Defender for Servers is set to 'On' # 8.1.3.2 Ensure that 'Vulnerability assessment for machines' component status is set to 'On' # 8.1.3.3 Ensure that 'Endpoint protection' component status is set to 'On' # 8.1.3.4 Ensure that 'Agentless scanning for machines' component status is set to 'On' # 8.1.3.5 Ensure that 'File Integrity Monitoring' component status is set to 'On' # 8.1.4.1 Ensure That Microsoft Defender for Containers Is Set To 'On' # 8.1.5.1 Ensure That Microsoft Defender for Storage Is Set To 'On' # 8.1.5.2 Ensure Advanced Threat Protection Alerts for Storage Accounts Are Monitored # 8.1.6.1 Ensure That Microsoft Defender for App Services Is Set To 'On' # 8.1.7.1 Ensure That Microsoft Defender for Azure Cosmos DB Is Set To 'On' # 8.1.7.2 Ensure That Microsoft Defender for Open-Source Relational Databases Is Set To 'On' # 8.1.7.3 Ensure That Microsoft Defender for (Managed Instance) Azure SQL Databases Is Set To 'On' # 8.1.7.4 Ensure That Microsoft Defender for SQL Servers on Machines Is Set To 'On' # 8.1.8.1 Ensure That Microsoft Defender for Key Vault Is Set To 'On' # 8.1.9.1 Ensure That Microsoft Defender for Resource Manager Is Set To 'On' # 8.1.10 Ensure that Microsoft Defender for Cloud is configured to check VM operating systems for updates # 8.1.11 Ensure that Microsoft Cloud Security Benchmark policies are not set to 'Disabled' # 8.1.12 Ensure That 'All users with the following roles' is set to 'Owner' # 8.1.13 Ensure 'Additional email addresses' is Configured with a Security Contact Email # 8.1.14 Ensure that 'Notify about alerts with the following severity (or higher)' is enabled # 8.1.15 Ensure that 'Notify about attack paths with the following risk level (or higher)' is enabled # 8.1.16 Ensure that Microsoft Defender External Attack Surface Monitoring (EASM) is enabled # 8.2.1 Ensure That Microsoft Defender for IoT Hub Is Set To 'On' # 8.3.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults # 8.3.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults. # 8.3.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults # 8.3.4 Ensure that the Expiration Date is set for all Secrets in Non- RBAC Key Vaults # 8.3.5 Ensure 'Purge protection' is set to 'Enabled' (Automated) # 8.3.6 Ensure that Role Based Access Control for Azure Key Vault is enabled # 8.3.7 Ensure Public Network Access is Disabled # 8.3.8 Ensure Private Endpoints are used to access Azure Key Vault # 8.3.9 Ensure automatic key rotation is enabled within Azure Key Vault # 8.3.10 Ensure that Azure Key Vault Managed HSM is used when required # 8.3.11 Ensure certificate 'Validity Period (in months)' is less than or equal to '12' # 8.4.1 Ensure an Azure Bastion Host Exists # 8.5 Ensure Azure DDoS Network Protection is enabled on virtual networks # # Refer to Section(s) 8.1-5 Page(s) 338-472 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_security_services () { print_function "audit_azure_security_services" check_message "Azure Security Services" # 8.1.1.1 Ensure Microsoft Defender CSPM is set to 'On' audit_azure_microsoft_defender # 8.1.3.2 Ensure that 'Vulnerability assessment for machines' component status is set to 'On' - TBD # 8.1.3.3 Ensure that 'Endpoint protection' component status is set to 'On' check_azure_security_setting_value "Endpoint protection" "WDATP" "enabled" "true" # 8.1.3.4 Ensure that 'Agentless scanning for machines' component status is set to 'On' check_azure_security_setting_value "Agentless scanning for machines" "CSPM" "enabled" "true" # 8.1.3.5 Ensure that 'File Integrity Monitoring' component status is set to 'On' - TBD # 8.1.5.2 Ensure Advanced Threat Protection Alerts for Storage Accounts Are Monitored - TBD # 8.1.11 Ensure that Microsoft Cloud Security Benchmark policies are not set to 'Disabled' - TBD # 8.1.12 Ensure That 'All users with the following roles' is set to 'Owner' # 8.1.13 Ensure 'Additional email addresses' is Configured with a Security Contact Email # 8.1.14 Ensure that 'Notify about alerts with the following severity (or higher)' is enabled audit_azure_security_contacts # 8.1.15 Ensure that 'Notify about attack paths with the following risk level (or higher)' is enabled - TBD # 8.3.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults # 8.3.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults # 8.3.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults # 8.3.4 Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults audit_azure_key_vault_keys # 8.3.5 Ensure that Purge Protection is enabled for all Key Vaults audit_azure_key_vault_purge_protection # 8.3.6 Ensure that Role Based Access Control for Azure Key Vault is enabled audit_azure_key_vault_rbac # 8.3.7 Ensure Public Network Access is Disabled audit_azure_key_vault_public_network_access } ================================================ FILE: modules/azure/security/audit_azure_user_access_admin_role.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_user_access_admin_role # # Check Azure User Access Administrator Role # # 5.3.3 Ensure that User Access Administrator Role is restricted # # Refer to Section(s) 5.3.3 Page(s) 115-6 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_user_access_admin_role () { print_function "audit_azure_user_access_admin_role" check_message "Azure User Access Administrator Role" command="az role assignment list --role \"User Access Administrator\" --scope \"/\" --output tsv" command_message "${command}" assignments=$( eval "${command}" ) if [ -z "${assignments}" ]; then inc_secure "User Access Administrator Role is restricted" else inc_insecure "User Access Administrator Role is not restricted" verbose_message "az role assignment delete --role \"User Access Administrator\" --scope \"/\"" "fix" fi } ================================================ FILE: modules/azure/security/audit_azure_waf.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_waf # # Check Azure WAF # # 7.10 Ensure Azure Web Application Firewall (WAF) is enabled on Azure Application Gateway # 7.13 Ensure 'HTTP2' is set to 'Enabled' on Azure Application Gateway # # Refer to Section(s) 7.10,13 Page(s) 319-21,325-7 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_waf () { print_function "audit_azure_waf" check_message "Azure WAF" command="az network application-gateway list --query '[].resourceGroup' --output tsv 2> /dev/null" command_message "${command}" res_groups=$( eval "${command}" ) if [ -z "${res_groups}" ]; then info_message "No WAF instances found" return fi for res_group in $res_groups; do command="az network application-gateway list --resource-group \"${res_group}\" --query '[].name' --output tsv 2> /dev/null" command_message "${command}" waf_list=$( eval "${command}" ) for waf_name in ${waf_list}; do check_azure_waf_value "" "${waf_name}" "${res_group}" "firewallPolicy.id" "ne" "" "" "" check_azure_waf_value "" "${waf_name}" "${res_group}" "enableHttp2" "eq" "true" "--http2" "Enabled" done done } ================================================ FILE: modules/azure/security/audit_azure_waf_inspection_policy.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_waf_inspection_policy # # Check Azure WAF Inspection Policy # # 7.14 Ensure request body inspection is enabled in Azure Web Application Firewall policy on Azure Application Gateway # 7.15 Ensure bot protection is enabled in Azure Web Application Firewall policy on Azure Application Gateway - TBD # # Refer to Section(s) 7.14-15 Page(s) 328-33 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_waf_inspection_policy () { print_function "audit_azure_waf_inspection_policy" check_message "Azure WAF Inspection Policy" command="az network application-gateway list --query '[].resourceGroup' --output tsv 2> /dev/null" command_message "${command}" res_groups=$( eval "${command}" ) if [ -z "${res_groups}" ]; then verbose_message "No WAF instances found" "info" return fi for res_group in ${res_groups}; do command="az network application-gateway list --resource-group \"${res_group}\" --query '[].name' --output tsv 2> /dev/null" command_message "${command}" waf_list=$( eval "{$command}" ) for waf_name in ${waf_list}; do command="az network application-gateway show --resource-group \"${res_group}\" --name \"${waf_name}\" --query 'firewallPolicy.id' --output tsv 2> /dev/null" command_message "${command}" waf_ids=$( eval "${command}" ) for waf_id in ${waf_ids}; do check_azure_waf_value "waf-policy" "${waf_id}" "" "policySettings.requestBodyCheck" "eq" "true" "request-body-check" "true" check_azure_waf_value "waf-policy" "${waf_id}" "" "managedRules.managedRuleSets" "eq" "Microsoft_BotManagerRuleSet" "" "" check_azure_waf_value "waf-policy" "${waf_id}" "" "managedRules.managedRuleSets" "ne" "Disabled" "" "" done done done } ================================================ FILE: modules/azure/security/audit_azure_waf_ssl_policy.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_waf_ssl_policy # # Check Azure WAF SSL Policy # # 7.12 Ensure the SSL policy's 'Min protocol version' is set to 'TLSv1_2' or higher on Azure Application Gateway # # Refer to Section(s) 7.12 Page(s) 322-4 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_waf_ssl_policy () { print_function "audit_azure_waf_ssl_policy" check_message "Azure WAF SSL Policy" command="az network application-gateway list --query '[].resourceGroup' --output tsv 2> /dev/null" command_message "${command}" res_groups=$( eval "${command}" ) if [ -z "${res_groups}" ]; then info_message "No WAF instances found" return fi for res_group in ${res_groups}; do command="az network application-gateway list --resource-group \"${res_group}\" --query '[].name' --output tsv 2> /dev/null" command_message "${command}" waf_list=$( eval "${command}" ) for waf_name in ${waf_list}; do check_azure_waf_value "ssl-policy" "${waf_name}" "${res_group}" "firewallPolicy.id" "ne" "" "" "" done done } ================================================ FILE: modules/azure/storage/audit_azure_blob_storage.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_blob_storage # # Check Azure Blob Storage # # 9.2.1 Ensure that soft delete for blobs on Azure Blob Storage storage accounts is Enabled # 9.2.2 Ensure that soft delete for containers on Azure Blob Storage storage accounts is Enabled # 9.2.3 Ensure 'Versioning' is set to 'Enabled' on Azure Blob Storage storage accounts # # Refer to Section(s) 9.2.1-3 Page(s) 485-95 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # 2.1.2.1.1 Ensure Critical Data is Encrypted with Microsoft Managed Keys - Needs verification # 11.3 Ensure that soft delete for blobs on Azure Blob Storage storage accounts is Enabled - TBD # 11.4 Ensure stored access policies (SAP) are used when generating shared access signature (SAS) tokens - TBD # 11.5 Ensure 'Versioning' is set to 'Enabled' on Azure Blob Storage storage accounts # 11.6 Ensure locked immutability policies are used for containers storing business-critical blob data # 17.5 Ensure that ‘Enable Infrastructure Encryption’ for Each Storage Blob in Azure Storage is Set to ‘enabled’ # 17.7 Ensure Soft Delete is Enabled for Azure Containers and Blob Storage # # Refer to Section(s) 2 Page(s) 25- CIS Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_blob_storage () { print_function "audit_azure_blob_storage" check_message "Azure Blob Storage" immutability_state="Locked" retention_days="7" command="az storage account list --query \"[].name\" --output tsv" command_message "${command}" s_accounts=$( eval "${command}" 2> /dev/null ) if [ -z "${s_accounts}" ]; then info_message "No Storage Accounts found" return fi for s_account in ${s_accounts}; do # 9.2.1 Ensure that soft delete for blobs on Azure Blob Storage storage accounts is Enabled # 17.7 Ensure Soft Delete is Enabled for Azure Containers and Blob Storage check_azure_storage_blob_policy_value "Soft delete" "${s_account}" "service-properties" "delete-policy" "enabled" "eq" "true" "--enable" check_azure_storage_blob_policy_value "Days retained" "${s_account}" "service-properties" "delete-policy" "days" "eq" "${retention_days}" "--days-retained" # 9.2.3 Ensure 'Versioning' is set to 'Enabled' on Azure Blob Storage storage accounts # 11.5 Ensure 'Versioning' is set to 'Enabled' on Azure Blob Storage storage accounts check_azure_storage_account_container_value "Versioning" "${s_account}" "" "service-properties" "isVersioningEnabled" "eq" "true" "--enable-versioning" # 9.2.2 Ensure that soft delete for containers on Azure Blob Storage storage accounts is Enabled command="az storage account show --name \"${s_account}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) if [ "${azure_auth_mode}" = "login" ]; then command="az storage container list --account-name \"${s_account}\" --query \"[].name\" --output tsv --auth-mode \"${azure_auth_mode}\"" command_message "${command}" c_names=$( eval "${command}" ) else command="az storage container list --account-name \"${s_account}\" --query \"[].name\" --output tsv" command_message "${command}" c_names=$( eval "${command}" ) fi for c_name in ${c_names}; do check_azure_storage_account_container_value "Soft delete" "${s_account}" "${res_group}" "service-properties" "containerDeleteRetentionPolicy.enabled" "eq" "true" "--enable-container-delete-retention" check_azure_storage_account_container_value "Days retained" "${s_account}" "${res_group}" "service-properties" "containerDeleteRetentionPolicy.days" "eq" "${retention_days}" "--container-delete-retention-days" # 2.1.2.1.1 Ensure Critical Data is Encrypted with Microsoft Managed Keys - Needs verification check_azure_storage_account_container_value "Data is encrytped with MMK" "${s_account}" "${res_group}" "encryptionScope.defaultEncryptionScope" "eq" "\$account-encryption-key" # 11.6 Ensure locked immutability policies are used for containers storing business-critical blob data check_azure_storage_account_container_value "Immutability policy state" "${s_account}" "${res_group}" "immutability-policy" "immutabilitySettings.state" "eq" "${immutability_state}" "--immutability-policy-state" # 17.5 Ensure that ‘Enable Infrastructure Encryption’ for Each Storage Blob in Azure Storage is Set to ‘enabled’ command="az storage blob list --container-name \"${c_name}\" --account-name \"${s_account}\" --query \"[].name\" --output tsv" command_message "${command}" blob_names=$( eval "${command}" ) for blob_name in ${blob_names}; do check_azure_storage_blob_value "Infrastructure encryption" "${s_account}" "${c_name}" "${blob_name}" "properties.serverEncrypted" "eq" "Enabled" done done done } ================================================ FILE: modules/azure/storage/audit_azure_data_factory.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_data_factory # # Check Azure Data Factory # # 4.1 Ensure Data Factory is encrypted using Customer Managed Keys # 4.2 Ensure Data Factory is using Managed Identities - TBD # 4.3 Ensure that Data Factory is using Azure Key Vault to store Credentials and Secrets - TBD # 4.4 Ensure that Data Factory is using RBAC to manage privilege assignment - TBD # # Refer to Section(s) 4 Page(s) 73- Microsoft Azure Database Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_data_factory () { print_function "audit_azure_data_factory" check_message "Azure Data Factory" command="az datafactory list --query \"[].name\" --output tsv" command_message "${command}" factory_names=$( eval "${command}" ) if [ -z "${factory_names}" ]; then info_message "No Data Factory instances found" return fi for factory_name in ${factory_names}; do command="az datafactory show --name \"${factory_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" resource_group=$( eval "${command}" ) # 4.1 Ensure Data Factory is encrypted using Customer Managed Keys check_data_factory_value "Customer-Managed Keys" "${factory_name}" "${resource_group}" "keyVaultKeyUri" "ne" "" "" # 4.2 Ensure Data Factory is using Managed Identities - TBD check_data_factory_value "Managed Identities" "${factory_name}" "${resource_group}" "identity.type" "eq" "${azure_managed_identity}" "" # 4.3 Ensure that Data Factory is using Azure Key Vault to store Credentials and Secrets - TBD check_data_factory_value "Using Azure Key Vault" "${factory_name}" "${resource_group}" "properties.type.baseUrl" "ne" "" "" # 4.4 Ensure that Data Factory is using RBAC to manage privilege assignment - TBD for item in principalName principalId principalType roleDefinitionName scope; do check_data_factory_value "Using RBAC" "${factory_name}" "${resource_group}" "[].${item}" "ne" "" "" done done } ================================================ FILE: modules/azure/storage/audit_azure_database_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_database_services # # Check Azure Database Services # # Refer to Section(s) 4 Page(s) 69 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # Redis # 2.1 Ensure 'Microsoft Entra Authentication' is 'Enabled' - TBD # 2.2 Ensure that 'Allow access only via SSL' is set to 'Yes' # 2.3 Ensure that 'Minimum TLS version' is set to '1.2' # 2.4 Ensure that 'Access Policies' are Implemented and Reviewed Periodically - TBD # 2.5 Ensure that 'System Assigned Managed Identity' is set to 'On' - TBD # 2.6 Ensure that 'Public Network Access' is 'Disabled' # 2.7 Ensure Azure Cache for Redis is Using a Private Link # 2.8 Ensure that Azure Cache for Redis is Using Customer-Managed Keys # 2.9 Ensure 'Access Keys Authentication' is set to 'Disabled' # 2.10 Ensure 'Update Channel' is set to 'Stable' # # Cosmos DB # 3.1 Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks # 3.2 Ensure that Cosmos DB uses Private Endpoints where possible # 3.3 Ensure that 'disableLocalAuth' is set to 'true' # 3.4 Ensure `Public Network Access` is `Disabled` # 3.5 Ensure critical data is encrypted with customer-managed keys (CMK) # 3.6 Ensure the firewall does not allow all network traffic # 3.7 Ensure that Cosmos DB Logging is Enabled # 3.8 Ensure Data Factory is encrypted using Customer Managed Keys # # Data Factory # 4.1 Ensure Data Factory is encrypted using Customer Managed Keys # 4.2 Ensure Data Factory is using Managed Identities - TBD # 4.3 Ensure that Data Factory is using Azure Key Vault to store Credentials and Secrets - TBD # 4.4 Ensure that Data Factory is using RBAC to manage privilege assignment - TBD # 5.2 Ensure Azure Database for MySQL uses only Microsoft Entra Authentication - TBD # # Azure Database for MySQL # 5.1 Ensure Azure Database for MySQL uses Customer Managed Keys for Encryption at Rest - TBD # 5.2 Ensure Azure Database for MySQL uses only Microsoft Entra Authentication - TBD # 5.3 Ensure `Public Network Access` is `Disabled` for Azure Database for MySQL - TBD # 5.4 Ensure Private Endpoints Are Used for Azure MySQL Databases - TBD # 5.5 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL flexible server - TBD # 5.6 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL flexible server - TBD # 5.7 Ensure server parameter 'error_server_log_file' is Enabled for MySQL Database Server - TBD # 5.8 Ensure server parameter 'require_secure_transport' is set to 'ON' for MySQL Server - TBD # 5.9 Ensure server parameter 'tls_version' is set to 'TLSv1.2' (or higher) for MySQL flexible server - TBD # # Azure Database for PostgreSQL # 6.1 Ensure Azure Database for PostgreSQL uses Customer Managed Keys for Encryption at Rest - TBD # 6.2 Ensure Azure Database for PostgreSQL uses only Microsoft Entra Authentication - TBD # 6.3 Ensure `Public Network Access` is `Disabled` for Azure Database for PostgreSQL - TBD # 6.4 Ensure Private Endpoints Are Used for Azure PostgreSQL Databases - TBD # 6.5 Ensure server parameter 'connection_throttle.enable' is set to 'ON' for PostgreSQL server - TBD # 6.6 Ensure server parameter 'logfiles.retention_days' is greater than 3 days for PostgreSQL server - TBD # 6.7 Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL server - TBD # 6.8 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL servers - TBD # 6.9 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL servers - TBD # 6.10 Ensure server parameter 'require_secure_transport' is set to 'ON' for PostgreSQL server - TBD # 6.11 Ensure server parameter 'tls_version' is set to 'TLSv1.2' (or higher) for PostgreSQL server - TBD # # Azure SQL Database # 9.1 Ensure that 'Auditing' is set to 'On' - TBD # 9.2 Ensure that 'Public Network Access' is set to 'Disable' - TBD # 9.3 Ensure no Azure SQL Database firewall rule is overly permissive - TBD # 9.4 Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key - TBD # 9.5 Ensure that Microsoft Entra authentication is Configured for SQL Servers - TBD # 9.6 Ensure that 'Data encryption' is set to 'On' on a SQL Database - TBD # 9.7 Ensure that 'Auditing' Retention is 'greater than 90 days' - TBD # 9.8 Ensure 'Minimum TLS Version' is set to 'TLS 1.2' or higher - TBD # # Refer to Section(s) 2- Page(s) 11- Microsoft Azure Database Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_database_services () { print_function "audit_azure_database_services" check_message "Azure Database Services" audit_azure_redis_cache audit_azure_cosmos_db audit_azure_data_factory audit_azure_mysql_db audit_azure_postgresql_db audit_azure_sql_db } ================================================ FILE: modules/azure/storage/audit_azure_databox.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_databox # # Check Azure Databox # # 12.1 Ensure double encryption is used for Azure Data Box in high-security environments - TBD # # Refer to Sections(s) 12 Page(s) 142-3 Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_databox () { print_function "audit_azure_databox" check_message "Azure Databox" command="az databox job list --query '[].id' --output tsv 2> /dev/null" command_message "${command}" job_ids=$( eval "${command}" ) if [ -z "${job_ids}" ]; then info_message "No Azure Databox job(s) found" return fi for job_id in ${job_ids}; do command="az databox job show --id ${job_id} --query '[].name' --output tsv 2> /dev/null" command_message "${command}" job_name=$( eval "${command}" ) command="az databox job show --id ${job_id} --query '[].resourceGroup' --output tsv 2> /dev/null" command_message "${command}" res_group=$( eval "${command}" ) check_azure_databox_value "Double encryption" "${job_name}" "${res_group}" "DoubleEncryptionEnabled" "eq" "true" done } ================================================ FILE: modules/azure/storage/audit_azure_databricks.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_databricks # # Check Azure Databricks workspaces # # 2.1.1 Ensure that Azure Databricks is deployed in a customer-managed virtual network (VNet) # 2.1.2 Ensure that network security groups are configured for Databricks subnets # 2.1.3 Ensure that traffic is encrypted between cluster worker nodes # 2.1.4 Ensure that users and groups are synced from Microsoft Entra ID to Azure Databricks # 2.1.5 Ensure that Unity Catalog is configured for Azure Databricks # 2.1.6 Ensure that usage is restricted and expiry is enforced for Databricks personal access tokens # 2.1.7 Ensure that diagnostic log delivery is configured for Azure Databricks # 2.1.8 Ensure critical data in Azure Databricks is encrypted with customer-managed keys # 2.1.9 Ensure 'No Public IP' is set to 'Enabled' # 2.1.10 Ensure 'Allow Public Network Access' is set to 'Disabled' # 2.1.11 Ensure private endpoints are used to access Azure Databricks workspaces # # Refer to Section(s) 2.1.1-11 Page(s) 27-62 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_databricks () { print_function "audit_azure_databricks" check_message "Azure Databricks" command="az databricks workspace list --query \"[].name\" --output tsv" command_message "${command}" space_list=$( eval "${command}" 2> /dev/null ) if [ -z "${space_list}" ]; then info_message "No Databricks workspaces found" return fi for space_name in ${space_list}; do command="az databricks workspace list --query \"[?contains(name, '${space_name}')].[resourceGroup]\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az databricks workspace list --query \"[?contains(name, '${space_name}')].[id]\" --output tsv" command_message "${command}" res_id=$( eval "${command}" ) # 2.1.1 Ensure that Azure Databricks is deployed in a customer-managed virtual network (VNet) - TBD # 2.1.2 Ensure that network security groups are configured for Databricks subnets - TBD # 2.1.3 Ensure that traffic is encrypted between cluster worker nodes - TBD # 2.1.4 Ensure that users and groups are synced from Microsoft Entra ID to Azure Databricks - TBD # 2.1.5 Ensure that Unity Catalog is configured for Azure Databricks # 2.1.6 Ensure that usage is restricted and expiry is enforced for Databricks personal access tokens - TBD # 2.1.7 Ensure that diagnostic log delivery is configured for Azure Databricks # 2.1.8 Ensure critical data in Azure Databricks is encrypted with customer-managed keys # 2.1.9 Ensure 'No Public IP' is set to 'Enabled' # 2.1.10 Ensure 'Allow Public Network Access' is set to 'Disabled' # 2.1.11 Ensure private endpoints are used to access Azure Databricks workspaces - Needs check of each endpoint check_azure_monitor_value "Diagnostic Log Delivery" "${space_name}" "${res_id}" "diagnostic-settings" "" "ne" "" "" check_azure_databricks_value "Customer Managed Keys" "${space_name}" "${res_group}" "encryption.keySource" "eq" "Microsoft.KeyVault." "" check_azure_databricks_value "No Public IP" "${space_name}" "${res_group}" "parameters.enableNoPublicIp.value" "eq" "true" "--enable-no-public-ip" check_azure_databricks_value "Allow Public Network Access" "${space_name}" "${res_group}" "publicNetworkAccess" "eq" "Disabled" "--public-network-access" check_azure_databricks_value "Private Endpoints" "${space_name}" "${res_group}" "privateEndpointConnections" "ne" "" "" done } ================================================ FILE: modules/azure/storage/audit_azure_elastic_san.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_elastic_san # # Check Azure Elastic SAN # # 2.2.1.1 Ensure public network access is Disabled # 15.1 Ensure 'Public network access' is set to 'Disabled' on Azure Elastic SAN # 15.2 Ensure customer-managed keys (CMK) are used to encrypt data at rest on Azure Elastic SAN volume groups # # Refer to Section(s) 2 Page(s) 25- CIS Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_elastic_san () { print_function "audit_azure_elastic_san" check_message "Azure Elastic SAN" command="az elastic-san list --query \"[].id\" --output tsv" command_message "${command}" san_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${san_ids}" ]; then info_message "No Elastic SANs found" return fi for san_id in ${san_ids}; do # 2.2.1.1 Ensure public network access is Disabled # 15.1 Ensure 'Public network access' is set to 'Disabled' on Azure Elastic SAN check_azure_elastic_san_value "Public Network Access" "${san_id}" "" "" "" "" "publicNetworkAccess" "eq" "Disabled" "--public-network-access" "" # 15.2 Ensure customer-managed keys (CMK) are used to encrypt data at rest on Azure Elastic SAN volume groups command="az elastic-san show --id \"${san_id}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az elastic-san show --id \"${san_id}\" --query \"[].name\" --output tsv" command_message "${command}" san_name=$( eval "${command}" ) command="az elastic-san volume-group list --resource-group \"${res_group}\" --elastic-san \"${san_name}\" --query \"[].name\" --output tsv" volume_group_names=$( eval "${command}" ) for volume_group_name in ${volume_group_names}; do check_azure_elastic_san_value "Customer Managed Keys" "" "${san_name}" "${res_group}" "${volume_group_name}" "encryption" "eq" "EncryptionAtRestWithCustomerManagedKey" "" "" done done } ================================================ FILE: modules/azure/storage/audit_azure_file_shares.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_file_shares # # Check Azure File Shares # # 9.1.1 Ensure soft delete for Azure File Shares is Enabled # 9.1.2 Ensure 'SMB protocol version' is set to 'SMB 3.1.1' or higher for SMB file shares # 9.1.3 Ensure 'SMB channel encryption' is set to 'AES-256-GCM' or higher for SMB file shares # # Refer to Section(s) 9.1.1-3 Page(s) 475-84 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # 8.2 Ensure root squash for NFS file shares is configured # 8.3 Ensure 'SMB protocol version' is set to 'SMB 3.1.1' or higher for SMB file shares # 8.4 Ensure 'SMB channel encryption' is set to 'AES-256-GCM' or higher for SMB file shares # # Refer to Sections(s) 8 Page(s) 106-19 Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_file_shares () { print_function "audit_azure_file_shares" check_message "Azure File Shares" command="az storage account list --query \"[].name\" --output tsv" command_message "${command}" s_accounts=$( eval "${command}" 2> /dev/null ) if [ -z "${s_accounts}" ]; then info_message "No Storage Accounts found" return fi for s_account in ${s_accounts}; do command="az storage account show --name \"${storage_account}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 9.1.1 Ensure soft delete for Azure File Shares is Enabled check_azure_file_share_value "Days retained" "${s_account}" "${res_group}" "service-properties" "shareDeleteRetentionPolicy.days" "eq" "7" "--share-delete-retention-days" "" check_azure_file_share_value "Soft Delete" "${s_account}" "${res_group}" "service-properties" "shareDeleteRetentionPolicy.enabled" "eq" "true" "--enable-share-delete-retention" "" command="az storage account file-service-properties show --name \"${s_account}\" --resource-group \"${res_group}\" |grep -i smb" command_message "${command}" protocol_check=$( eval "${command}" ) if [ -n "${protocol_check}" ]; then # 9.1.2 Ensure 'SMB protocol version' is set to 'SMB 3.1.1' or higher for SMB file shares # 8.3 Ensure 'SMB protocol version' is set to 'SMB 3.1.1' or higher for SMB file shares check_azure_file_share_value "SMB Protocol Version" "${s_account}" "${res_group}" "service-properties" "protocolSettings.smb.versions" "eq" "SMB3.1.1" "--versions" # 9.1.3 Ensure 'SMB channel encryption' is set to 'AES-256-GCM' or higher for SMB file shares # 8.4 Ensure 'SMB channel encryption' is set to 'AES-256-GCM' or higher for SMB file shares check_azure_file_share_value "SMB Channel Encryption" "${s_account}" "${res_group}" "service-properties" "protocolSettings.smb.channelEncryption" "eq" "AES-256-GCM" "--channel-encryption" fi command="az storage account file-service-properties show --name \"${s_account}\" --resource-group \"${res_group}\" |grep -i nfs" command_message "${command}" protocol_check=$( eval "${command}" ) if [ -n "${protocol_check}" ]; then # 8.2 Ensure root squash for NFS file shares is configured check_azure_file_share_value "NFS Root Squash" "${s_account}" "${res_group}" "service-properties" "protocolSettings.nfs.rootSquash" "eq" "RootSquash" "rootSquash" fi done } ================================================ FILE: modules/azure/storage/audit_azure_managed_lustre.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_managed_lustre # # Check Azure Managed Lustre # # 4.1 Ensure 'Key encryption key' is set to a customer-managed key for Azure Managed Lustre file systems # # Refer to Section(s) 4.1 Page(s) 53-6 CIS Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_managed_lustre () { print_function "audit_azure_managed_lustre" check_message "Azure Managed Lustre" command="az storage account list --query \"[].name\" --output tsv" command_message "${command}" s_accounts=$( eval "${command}" 2> /dev/null ) if [ -z "${s_accounts}" ]; then info_message "No Storage Accounts found" return fi for s_account in ${s_accounts}; do command="az amlfs list --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_groups=$( eval "${command}" ) if [ -z "${resource_groups}" ]; then info_message "No Managed Lustre instances found" return fi for res_group in ${res_groups}; do command="az amlfs list --resource-group \"${res_group}\" --query \"[].name\" --output tsv" command_message "${command}" file_systems=$( eval "${command}" ) for file_system in ${file_systems}; do # 4.1 Ensure 'Key encryption key' is set to a customer-managed key for Azure Managed Lustre file systems check_azure_storage_fs_value "Key encryption key name" "${s_account}" "${file_system}" "encryption.keyEncryptionKeyId.keyName" "ne" "" check_azure_storage_fs_value "Key encryption key vault uri" "${s_account}" "${file_system}" "encryption.keyEncryptionKeyId.keyVaultUri" "ne" "" done done done } ================================================ FILE: modules/azure/storage/audit_azure_netapp_files.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_netapp_files # # Check Azure NetApp Files # # 10.1 Ensure 'Encryption key source' is set to 'Customer Managed Key' for Azure NetApp Files accounts # # Refer to Sections(s) 10 Page(s) 120-4 Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_netapp_files () { print_function "audit_azure_netapp_files" check_message "Azure NetApp Files" command="az netappfiles account list --query \"[].name\" --output tsv" command_message "${command}" s_accounts=$( eval "${command}" ) if [ -z "${s_accounts}" ]; then info_message "No NetApp Files instances found" return fi for s_account in ${s_accounts}; do command="az netappfiles account show --name \"${s_account}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 10.1 Ensure 'Encryption key source' is set to 'Customer Managed Key' for Azure NetApp Files accounts check_azure_netapp_file_value "Encryption key source" "${s_account}" "${res_group}" "encryptionKeySource" "eq" "CustomerManagedKey" done } ================================================ FILE: modules/azure/storage/audit_azure_storage_account_locks.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_storage_account_locks # # Audit Azure Storage Account Locks # # 17.14 Ensure Azure Resource Manager Delete locks are applied to Azure Storage Accounts # 17.15 Ensure Azure Resource Manager Read-only locks are applied to Azure Storage Accounts # # Refer to Section(s) 17.14-15 Page(s) 224-8 CIS Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured # audit_azure_storage_account_locks () { print_function "audit_azure_storage_account_locks" check_message "Azure Storage Account Locks" res_type="Microsoft.Storage/storageAccounts" audit_azure_locks "${res_type}" "CanNotDelete" audit_azure_locks "${res_type}" "ReadOnly" } ================================================ FILE: modules/azure/storage/audit_azure_storage_accounts.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_storage_accounts # # Check Azure Storage Accounts # # 9.3.1.1 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account # 9.3.1.2 Ensure that Storage Account access keys are periodically regenerated # 9.3.1.3 Ensure 'Allow storage account key access' for Azure Storage Accounts is 'Disabled' # 9.3.2.1 Ensure Private Endpoints are used to access Storage Accounts # 9.3.2.2 Ensure that 'Public Network Access' is 'Disabled' for storage accounts # 9.3.2.3 Ensure default network access rule for storage accounts is set to deny # 9.3.3.1 Ensure that 'Default to Microsoft Entra authorization in the Azure portal' is set to 'Enabled' # 9.3.4 Ensure that 'Secure transfer required' is set to 'Enabled' # 9.3.5 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access # 9.3.6 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' # 9.3.7 Ensure 'Cross Tenant Replication' is not enabled (Automated) # 9.3.8 Ensure that 'Allow Blob Anonymous Access' is set to 'Disabled' # 9.3.9 Ensure Azure Resource Manager Delete locks are applied to Azure Storage Accounts # 9.3.10 Ensure Azure Resource Manager ReadOnly locks are considered for Azure Storage Accounts # 9.3.11 Ensure Redundancy is set to 'geo-redundant storage (GRS)' on critical Azure Storage Accounts # # Refer to Section(s) 9.3.1-9.3.11 Page(s) 497-549 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # 2.1.1.1 Ensure 'Allowed Protocols' for shared access signature (SAS) tokens is set to 'HTTPS Only' # 2.1.1.3 Ensure stored access policies (SAP) are used when generating shared access signature (SAS) tokens - Needs verification # 2.2.1.1 Ensure public network access is Disabled # 2.2.1.2 Ensure Network Access Rules are set to Deny-by-default # 11.1 Ensure 'Allowed Protocols' for shared access signature (SAS) tokens is set to 'HTTPS Only' - TBD # 11.2 Ensure that shared access signature (SAS) tokens expire within an hour - TBD # 17.1.1 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account # 17.1.2 Ensure 'Allowed Protocols' for shared access signature (SAS) tokens is set to 'HTTPS Only' # 17.1.3 Ensure that Storage Account Access Keys are Periodically Regenerated # 17.1.4 Ensure that shared access signature (SAS) tokens expire within an hour - TBD # 17.1.5 Ensure 'Allow storage account key access' for Azure Storage Accounts is 'Disabled' # 17.1.6 Ensure Storage for Critical Data are Encrypted with Customer Managed Keys (CMK) - TBD # 17.2.1 Ensure Private Endpoints are used to access Storage Accounts # 17.2.2 Ensure that 'Public Network Access' is 'Disabled' for storage accounts # 17.2.3 Ensure default network access rule for storage accounts is set to deny # 17.4 Ensure that 'Secure transfer required' is set to 'Enabled' # 17.5 Ensure that ‘Enable Infrastructure Encryption’ for Each Storage Account in Azure Storage is Set to ‘enabled’ # 17.6 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access # 17.11 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' # 17.12 Ensure 'Cross Tenant Replication' is not enabled # 17.13 Ensure that 'Allow Blob Anonymous Access' is set to 'Disabled' # 17.16 Ensure Redundancy is set to 'geo-redundant storage (GRS)' on critical Azure Storage Accounts # 18.1 Ensure that shared access signature (SAS) tokens expire within an hour - TBD # 18.2 Ensure that stored access policies (SAP) are used when generating shared access signature (SAS) tokens - TBD # 18.3 Ensure Storage Explorer is using the latest version - TBD # # Refer to Section(s) 2-19 Page(s) 25-240 CIS Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_storage_accounts () { print_function "audit_azure_storage_accounts" check_message "Azure Storage Accounts" key_rotation="90" # days sas_expiration="1" # hours command="az storage account list --query \"[].name\" --output tsv" command_message "${command}" s_accounts=$( eval "${command}" ) if [ -z "${s_accounts}" ]; then info_message "No Storage Accounts found" return fi for s_account in ${s_accounts}; do command="az storage account show --name \"${s_account}\" --query \"id\" --output tsv" command_message "${command}" res_id=$( eval "${command}" ) command="az storage account show --name \"${s_account}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) # 9.3.1.2 Ensure that Storage Account access keys are periodically regenerated # 17.1.3 Ensure that Storage Account Access Keys are Periodically Regenerated check_azure_storage_account_keys_rotation "${s_account}" "${res_id}" "${key_rotation}" # 9.3.1.1 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account # 17.1.1 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account check_azure_storage_account_value "Enable key rotation reminders" "${s_account}" "${res_group}" "keyPolicy.keyExpirationPeriodInDays" "eq" "${key_rotation}" "--key-expiration-period-in-days" # 9.3.1.3 Ensure 'Allow storage account key access' for Azure Storage Accounts is 'Disabled' # 17.1.5 Ensure 'Allow storage account key access' for Azure Storage Accounts is 'Disabled' check_azure_storage_account_value "Allow storage account key access" "${s_account}" "${res_group}" "allowSharedKeyAccess" "eq" "false" "--allow-shared-key-access" # 9.3.2.1 Ensure Private Endpoints are used to access Storage Accounts # 17.2.1 Ensure Private Endpoints are used to access Storage Accounts check_azure_storage_account_value "Private Endpoints are used to access" "${s_account}" "${res_group}" "privateEndpointConnections[0].id" "ne" "" "" # 9.3.2.2 Ensure that 'Public Network Access' is 'Disabled' for storage accounts # 17.2.2 Ensure that 'Public Network Access' is 'Disabled' for storage accounts # 2.2.1.1 Ensure public network access is Disabled check_azure_storage_account_value "Public Network Access" "${s_account}" "${res_group}" "publicNetworkAccess" "eq" "Disabled" "--public-network-access" # 9.3.2.3 Ensure default network access rule for storage accounts is set to deny # 17.2.3 Ensure default network access rule for storage accounts is set to deny check_azure_storage_account_value "Default network access rule" "${s_account}" "${res_group}" "networkRuleSet.defaultAction" "eq" "Deny" "--default-action" # 9.3.3.1 Ensure that 'Default to Microsoft Entra authorization in the Azure portal' is set to 'Enabled' check_azure_storage_account_value "Microsoft Entra authorization" "${s_account}" "${res_group}" "defaultToOAuthAuthentication" "eq" "true" "defaultToOAuthAuthentication" # 9.3.4 Ensure that 'Secure transfer required' is set to 'Enabled' check_azure_storage_account_value "Secure transfer required" "${s_account}" "${res_group}" "enableHttpsTrafficOnly" "eq" "true" "--https-only" # 9.3.5 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access # 17.6 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access check_azure_storage_account_value "Azure services on the trusted services list" "${s_account}" "${res_group}" "networkRuleSet.bypass" "eq" "AzureServices" "--bypass" # 9.3.6 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' # 17.11 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' check_azure_storage_account_value "Minimum TLS version" "${s_account}" "${res_group}" "minimumTlsVersion" "eq" "TLS1_2" "--minimum-tls-version" # 9.3.7 Ensure 'Cross Tenant Replication' is not enabled # 17.12 Ensure 'Cross Tenant Replication' is not enabled check_azure_storage_account_value "Cross Tenant Replication" "${s_account}" "${res_group}" "allowCrossTenantReplication" "eq" "false" "--allow-cross-tenant-replication" # 9.3.8 Ensure 'Allow blob public access' is set to 'Disabled' # 17.13 Ensure that 'Allow Blob Anonymous Access' is set to 'Disabled' check_azure_storage_account_value "Allow Blob Public Access" "${s_account}" "${res_group}" "allowBlobPublicAccess" "eq" "false" "allowBlobPublicAccess" # 9.3.9 Ensure Azure Resource Manager Delete locks are applied to Azure Storage Accounts check_azure_resource_manager_lock "Azure Resource Manager Delete locks are applied" "${s_account}" "${res_group}" "[].level" "eq" "CanNotDelete" "Microsoft.Storage/storageAccounts" # 9.3.10 Ensure Azure Resource Manager ReadOnly locks are applied to Azure Storage Accounts check_azure_resource_manager_lock "Azure Resource Manager ReadOnly locks are applied" "${s_account}" "${res_group}" "[].level" "eq" "ReadOnly" "Microsoft.Storage/storageAccounts" # 9.3.11 Ensure Redundancy is set to 'geo-redundant storage (GRS)' on critical Azure Storage Accounts # 17.16 Ensure Redundancy is set to 'geo-redundant storage (GRS)' on critical Azure Storage Accounts check_azure_storage_account_value "Redundancy is set to geo-redundant storage (GRS)" "${s_account}" "${res_group}" "sku.name" "eq" "Standard_GRS" "--sku" # 2.1.1.1 Ensure 'Allowed Protocols' for shared access signature (SAS) tokens is set to 'HTTPS Only' # 17.1.2 Ensure 'Allowed Protocols' for shared access signature (SAS) tokens is set to 'HTTPS Only' check_azure_storage_account_value "Allow Shared Key Access" "${s_account}" "${res_group}" "allowSharedKeyAccess" "eq" "false" "" # 17.4 Ensure that 'Secure transfer required' is set to 'Enabled' check_azure_storage_account_value "Allowed Protocols for SAS tokens is HTTPS Only" "${s_account}" "${res_group}" "enableHttpsTrafficOnly" "eq" "true" "" # 2.1.1.3 Ensure stored access policies (SAP) are used when generating shared access signature (SAS) tokens - Need verification check_azure_storage_account_value "SAP are used when generating SAS tokens" "${s_account}" "${res_group}" "sasPolicy" "ne" "" "" # 2.2.1.2 Ensure Network Access Rules are set to Deny-by-default check_azure_storage_account_value "Network Access Rules are set to Deny-by-default" "${s_account}" "${res_group}" "networkRuleSet.defaultAction" "eq" "Deny" " --default-action" # 17.5 Ensure that ‘Enable Infrastructure Encryption’ for Each Storage Account in Azure Storage is Set to ‘enabled’ check_azure_storage_account_value "Enable Infrastructure Encryption" "${s_account}" "${res_group}" "encryption.infrastructureEncryption.enabled" "eq" "true" "infrastructureEncryptionEnabled" done } ================================================ FILE: modules/azure/storage/audit_azure_storage_logging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_storage_logging # # Check Azure Storage Logging # # 17.8 Ensure Storage Logging is Enabled for Queue Service for 'Read', 'Write', and 'Delete' requests # 17.9 Ensure Storage Logging is Enabled for Blob Service for 'Read', 'Write', and 'Delete' requests # 17.10 Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' Requests # # Refer to Section(s) 17.8 Page(s) 205-13 Microsoft Azure Storage Services Benchmark v1.0.0 # # Refer to CIS Microsoft Azure Compute Services Benchmark #. audit_azure_storage_logging () { print_function "audit_azure_storage_logging" check_message "Azure Storage Logging" retention_days="90" log_value="rwd" command="az storage account list --query \"[].name\" --output tsv" command_message "${command}" s_accounts=$( eval "${command}" ) if [ -z "${s_accounts}" ]; then info_message "No Storage Accounts found" return fi for s_account in ${s_accounts}; do # 17.8 Ensure Storage Logging is Enabled for Queue Service for 'Read', 'Write', and 'Delete' requests # 17.9 Ensure Storage Logging is Enabled for Blob Service for 'Read', 'Write', and 'Delete' requests # 17.10 Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' Requests for service_type in queue blob table; do for request_type in read write delete; do check_azure_storage_logging_value "Storage Logging" "${s_account}" "${service_type}" "[].${service_type}.${request_type}" "eq" "true" "" done check_azure_storage_logging_value "Storage Logging" "${s_account}" "${service_type}" "[].${service_type}.retentionPolicy.days" "eq" "${retention_days}" "${log_value}" done done } ================================================ FILE: modules/azure/storage/audit_azure_storage_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_storage_services # # Check Azure Storage Services # # 9.1.1 Ensure soft delete for Azure File Shares is Enabled # 9.1.2 Ensure 'SMB protocol version' is set to 'SMB 3.1.1' or higher for SMB file shares # 9.1.3 Ensure 'SMB channel encryption' is set to 'AES-256-GCM' or higher for SMB file shares # 9.2.1 Ensure that soft delete for blobs on Azure Blob Storage storage accounts is Enabled # 9.2.2 Ensure that soft delete for containers on Azure Blob Storage storage accounts is Enabled # 9.2.3 Ensure 'Versioning' is set to 'Enabled' on Azure Blob Storage storage accounts # 9.3.1.1 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account # 9.3.1.2 Ensure that Storage Account access keys are periodically regenerated # 9.3.1.3 Ensure 'Allow storage account key access' for Azure Storage Accounts is 'Disabled' # 9.3.2.1 Ensure Private Endpoints are used to access Storage Accounts # 9.3.2.2 Ensure that 'Public Network Access' is 'Disabled' for storage accounts # 9.3.2.3 Ensure default network access rule for storage accounts is set to deny # 9.3.3.1 Ensure that 'Default to Microsoft Entra authorization in the Azure portal' is set to 'Enabled' # 9.3.4 Ensure that 'Secure transfer required' is set to 'Enabled' # 9.3.5 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access # 9.3.6 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' # 9.3.7 Ensure 'Cross Tenant Replication' is not enabled (Automated) # 9.3.8 Ensure that 'Allow Blob Anonymous Access' is set to 'Disabled' # 9.3.9 Ensure Azure Resource Manager Delete locks are applied to Azure Storage Accounts # 9.3.10 Ensure Azure Resource Manager ReadOnly locks are considered for Azure Storage Accounts # 9.3.11 Ensure Redundancy is set to 'geo-redundant storage (GRS)' on critical Azure Storage Accounts # # Refer to Section(s) 9 Page(s) 473-549 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # Secrets and Keys # Shared Access Signatures # 2.1.1.1 Ensure 'Allowed Protocols' for shared access signature (SAS) tokens is set to 'HTTPS Only' # 2.1.1.2 Ensure that shared access signature (SAS) tokens expire within an hour - TBD # 2.1.1.3 Ensure stored access policies (SAP) are used when generating shared access signature (SAS) tokens - Needs verification # 2.1.2.1.1 Ensure Critical Data is Encrypted with Microsoft Managed Keys - Needs verification # 2.1.2.2.1 Ensure Critical Data is Encrypted with Customer Managed Keys - TBD # 2.2.1.1 Ensure public network access is Disabled # Azure Managed Lustre # 4.1.1 Ensure 'Key encryption key' is set to a customer-managed key for Azure Managed Lustre file systems # 5.1.1 Ensure soft delete on Backup vaults is Enabled # Azure Backup # Backup Vaults # 5.1.2 Ensure immutability for Backup vaults is Enabled # 5.1.3 Ensure backup data in Backup vaults is encrypted using customer-managed keys (CMK) # 5.1.4 Ensure 'Use infrastructure encryption for this vault' is enabled on Backup vaults # 5.1.5 Ensure 'Cross Region Restore' is set to 'Enabled' on Backup vaults # 5.1.6 Ensure 'Cross Subscription Restore' is set to 'Disabled' or 'Permanently Disabled' on Backup vaults # 5.2.1 Ensure soft delete on Recovery Services vaults is Enabled # Recovery Services Vaults # 5.2.2 Ensure immutability for Recovery Services vaults is Enabled # 5.2.3 Ensure backup data in Recovery Services vaults is encrypted using customer-managed keys (CMK) # 5.2.4 Ensure 'Use infrastructure encryption for this vault' is enabled on Recovery Services vaults # 5.2.5 Ensure public network access on Recovery Services vaults is Disabled # 5.2.6 Ensure 'Cross Region Restore' is set to 'Enabled' on Recovery Services vaults # 5.2.7 Ensure 'Cross Subscription Restore' is set to 'Disabled' or 'Permanently Disabled' on Recovery Services vaults # Azure Files # 8.1 Ensure soft delete for Azure File Shares is Enabled # 8.2 Ensure root squash for NFS file shares is configured # 8.3 Ensure 'SMB protocol version' is set to 'SMB 3.1.1' or higher for SMB file shares # 8.4 Ensure 'SMB channel encryption' is set to 'AES-256-GCM' or higher for SMB file shares # Azure NetApp Files # 10.1 Ensure 'Encryption key source' is set to 'Customer Managed Key' for Azure NetApp Files accounts # Azure Blob Storage # 11.1 Ensure 'Allowed Protocols' for shared access signature (SAS) tokens is set to 'HTTPS Only' # 11.2 Ensure that shared access signature (SAS) tokens expire within an hour - TBD # 11.3 Ensure that soft delete for blobs on Azure Blob Storage storage accounts is Enabled # 11.4 Ensure stored access policies (SAP) are used when generating shared access signature (SAS) tokens - TBD # 11.5 Ensure 'Versioning' is set to 'Enabled' on Azure Blob Storage storage accounts # 11.6 Ensure locked immutability policies are used for containers storing business-critical blob data # Azure Data Box # 12.1 Ensure double encryption is used for Azure Data Box in high-security environments - TBD # Azure Elastic SAN # 15.1 Ensure 'Public network access' is set to 'Disabled' on Azure Elastic SAN # 15.2 Ensure customer-managed keys (CMK) are used to encrypt data at rest on Azure Elastic SAN volume groups # Queue Storage # 16.1 Ensure 'Allowed Protocols' for shared access signature (SAS) tokens is set to 'HTTPS Only' - TBD # 16.2 Ensure that shared access signature (SAS) tokens expire within an hour - TBD # 16.3 Ensure stored access policies (SAP) are used when generating shared access signature (SAS) tokens - TBD # Storage Accounts # Secrets and Keys # 17.1.1 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account # 17.1.2 Ensure 'Allowed Protocols' for shared access signature (SAS) tokens is set to 'HTTPS Only' # 17.1.3 Ensure that Storage Account Access Keys are Periodically Regenerated # 17.1.4 Ensure that shared access signature (SAS) tokens expire within an hour # 17.1.5 Ensure 'Allow storage account key access' for Azure Storage Accounts is 'Disabled' # 17.1.6 Ensure Storage for Critical Data are Encrypted with Customer Managed Keys (CMK) # Networking # 17.2.1 Ensure Private Endpoints are used to access Storage Accounts # 17.2.2 Ensure that 'Public Network Access' is 'Disabled' for storage accounts # 17.2.3 Ensure default network access rule for storage accounts is set to deny # Identity and Access Management # 17.4 Ensure that 'Secure transfer required' is set to 'Enabled' # 17.5 Ensure that ‘Enable Infrastructure Encryption’ for Each Storage Account in Azure Storage is Set to ‘enabled’ # 17.8 Ensure Storage Logging is Enabled for Queue Service for 'Read', 'Write', and 'Delete' requests # 17.9 Ensure Storage Logging is Enabled for Blob Service for 'Read', 'Write', and 'Delete' requests # 17.10 Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' Requests # 17.11 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' # 17.12 Ensure 'Cross Tenant Replication' is not enabled # 17.13 Ensure that 'Allow Blob Anonymous Access' is set to 'Disabled' # 17.14 Ensure Azure Resource Manager Delete locks are applied to Azure Storage Accounts # 17.15 Ensure Azure Resource Manager Read-only locks are applied to Azure Storage Accounts # # Refer to Sections(s) 2 Page(s) 25- Microsoft Azure Storage Services Benchmark v1.0.0 # # Refer to CIS Microsoft Azure Compute Services Benchmark #. audit_azure_storage_services () { print_function "audit_azure_storage_services" check_message "Azure Storage Services" audit_azure_databricks audit_azure_blob_storage audit_azure_file_shares audit_azure_storage_accounts audit_azure_recovery_services_vaults audit_azure_managed_lustre audit_azure_backup_vaults audit_azure_netapp_files audit_azure_databox audit_azure_elastic_san audit_azure_storage_logging audit_azure_storage_accounts_locks } ================================================ FILE: modules/azure/vaults/audit_azure_backup_vaults.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_backup_vaults # # Check Azure Backup Vaults # # 5.1.1 Ensure soft delete on Backup vaults is Enabled # 5.1.2 Ensure immutability for Backup vaults is Enabled # 5.1.3 Ensure backup data in Backup vaults is encrypted using customer-managed keys (CMK) # 5.1.4 Ensure 'Use infrastructure encryption for this vault' is enabled on Backup vaults # 5.1.5 Ensure 'Cross Region Restore' is set to 'Enabled' on Backup vaults # 5.1.6 Ensure 'Cross Subscription Restore' is set to 'Disabled' or 'Permanently Disabled' on Backup vaults # # Refer to Section(s) 2 Page(s) 25- CIS Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_backup_vaults () { print_function "audit_azure_backup_vaults" check_message "Azure Backup Vaults" immutability_state="Locked" retention_days="90" command="az dataprotection backup-vault list --query \"[].id\" --output tsv" command_message "${command}" vault_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${vault_ids}" ]; then info_message "No Backup Vaults found" return fi for vault_id in ${vault_ids}; do command="az dataprotection backup-vault show --id \"${vault_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az dataprotection backup-vault show --id \"${vault_id}\" --query \"name\" --output tsv" command_message "${command}" vault_name=$( eval "${command}" ) # 5.1.1 Ensure soft delete on Backup vaults is Enabled check_azure_backup_vault_value "Soft Delete" "${vault_name}" "${res_group}" "properties.encryption.keyUri" "ne" "" "" # 5.1.3 Ensure backup data in Backup vaults is encrypted using customer-managed keys (CMK) check_azure_backup_vault_value "Customer Managed Keys" "${vault_name}" "${res_group}" "properties.softDeleteFeatureState" "eq" "Enabled" "properties.softDeleteFeatureState" # 5.1.4 Ensure 'Use infrastructure encryption for this vault' is enabled on Backup vaults check_azure_backup_vault_value "Infrastructure Encryption" "${vault_name}" "${res_group}" "properties.infrastructureEncryptionEnabled" "eq" "true" "--infrastructure-encryption-enabled" # 5.1.5 Ensure 'Cross Region Restore' is set to 'Enabled' on Backup vaults check_azure_backup_vault_value "Cross Region Restore" "${vault_name}" "${res_group}" "properties.crossRegionRestoreFlag" "eq" "Enabled" "properties.crossRegionRestoreFlag" # 5.1.6 Ensure 'Cross Subscription Restore' is set to 'Disabled' or 'Permanently Disabled' on Backup vaults check_azure_backup_vault_value "Cross Subscription Restore" "${vault_name}" "${res_group}" "properties.crossSubscriptionRestoreFlag" "eq" "Disabled" "properties.crossSubscriptionRestoreFlag" # 5.1.2 Ensure immutability for Backup vaults is Enabled command="az backup policy list --vault-name \"${vault_name}\" --resource-group \"${res_group}\" --query \"[].name\" --output tsv" command_message "${command}" policy_names=$( eval "${command}" ) for policy_name in ${policy_names}; do check_azure_backup_policy_value "Immutability Settings" "${policy_name}" "${vault_name}" "${res_group}" "immutabilitySettings" "ne" "" "" check_azure_backup_policy_value "Immutability State" "${policy_name}" "${vault_name}" "${res_group}" "immutabilitySettings.state" "eq" "${immutability_state}" "--immutability-state" check_azure_backup_policy_value "Immutability Retention Duration" "${policy_name}" "${vault_name}" "${res_group}" "immutabilitySettings.retentionDurationInDays" "eq" "${retention_days}" "--retention-days" done done } ================================================ FILE: modules/azure/vaults/audit_azure_key_vault_certificates.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_key_vault_certificates # # Check Azure Key Vault Certificates # # 2.5 Ensure Azure Key Vaults are Used to Store Secrets # # Refer to Section(s) 2.5 Page(s) 238-42 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured # Audit account needs to have the 'Key Vault Reader' role # To do any changes to the key vaults, the 'Key Vault Administrator' role is required #. audit_azure_key_vault_certificates () { print_function "audit_azure_key_vault_certificates" check_message "Azure Key Vault Certificates" command="az keyvault list --query \"[].id\" --output tsv" command_message "${command}" key_vaults=$( eval "${command}" 2> /dev/null ) if [ -z "${key_vaults}" ]; then insecure_message "No Key Vault Certificates found" else secure_message "Key Vault Certificates found" fi } ================================================ FILE: modules/azure/vaults/audit_azure_key_vault_keys.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_key_vault_keys # # Check Azure Key Vault Keys # # 8.3.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults # 8.3.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults # 8.3.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults # 8.3.4 Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults # 8.3.9 Ensure automatic key rotation is enabled within Azure Key Vault # # Refer to Section(s) 8.3.1-4,9 Page(s) 425-39,456-9 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # Azure and NIST recommend that keys be rotated every two years or less. Refer to # 'Table 1: Suggested cryptoperiods for key types' on page 46 of the following document # for more information: # https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r5.pdf # # This requires the Azure CLI to be installed and configured # Audit account needs to have the 'Key Vault Reader' role # To do any changes to the key vaults, the 'Key Vault Administrator' role is required #. audit_azure_key_vault_keys () { print_function "audit_azure_key_vault_keys" check_message "Azure Key Vault Keys" command="az keyvault list --query \"[].name\" --output tsv" command_message "${command}" key_vaults=$( eval "${command}" 2> /dev/null ) if [ -z "${key_vaults}" ]; then info_message "No Key Vaults found" return fi for key_vault in ${key_vaults}; do command="az keyvault key list --vault-name \"${key_vault}\" --query \"[].name\" --output tsv" command_message "${command}" key_list=$( eval "${command}" ) for key_name in ${key_list}; do check_azure_key_vault_key_value "${key_vault}" "${key_name}" "attributes.enabled" "eq" "true" "" "" check_azure_key_vault_key_value "${key_vault}" "${key_name}" "attributes.expired" "ne" "" "" "" check_azure_key_vault_key_value "${key_vault}" "${key_name}" "" "ne" "" "rotation-policy" "Notify" check_azure_key_vault_key_value "${key_vault}" "${key_name}" "timeAfterCreate" "ne" "" "rotation-policy" "Notify" check_azure_key_vault_key_value "${key_vault}" "${key_name}" "" "ne" "" "rotation-policy" "Rotate" check_azure_key_vault_key_value "${key_vault}" "${key_name}" "timeAfterCreate" "ne" "" "rotation-policy" "Rotate" done done } ================================================ FILE: modules/azure/vaults/audit_azure_key_vault_logging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_key_vault_logging # # Check Azure Key Vault Logging # # 6.1.1.4 Ensure that logging for Azure Key Vault is 'Enabled' # # Refer to Section(s) 6.1.1.4 Page(s) 207-10 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_key_vault_logging () { print_function "audit_azure_key_vault_logging" check_message "Azure Key Vault Logging" command="az keyvault list --query \"[].id\" --output tsv 2>/dev/null" command_message "${command}" vault_ids=$( eval "${command}" 2> /dev/null ) if [ -z "${vault_ids}" ]; then info_message "No Key Vaults found" return fi for vault_id in ${vault_ids}; do command="az monitor diagnostic-settings list --resource \"${vault_id}\" --query \"[].name\" --output tsv 2>/dev/null" command_message "${command}" res_names=$( eval "${command}" ) for res_name in ${res_names}; do command="az monitor diagnostic-settings show --resource \"${vault_id}\" --name \"${res_name}\" --query \"logs\" --output tsv 2>/dev/null" command_message "${command}" az monitor diagnostic-settings show --resource "${vault_id}" --name "${res_name}" --query "logs" --output tsv 2>/dev/null | while read -r line; do category=$( echo "${line}" | awk '{print $1}' ) enabled=$( echo "${line}" | awk '{print $2}' ) if [ "${enabled}" = "True" ]; then inc_secure "Key Vault \"${res_name}\" logging enabled for \"${category}\"" else inc_insecure "Key Vault \"${res_name}\" logging disabled for \"${category}\"" fi done done done } ================================================ FILE: modules/azure/vaults/audit_azure_key_vault_private_endpoints.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_key_vault_private_endpoints # # Check Azure Key Vault Private Endpoints # # 8.3.7 Ensure Public Network Access is Disabled # # Refer to Section(s) 8.3.7 Page(s) 447-50 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured # Audit account needs to have the 'Key Vault Reader' role # To do any changes to the key vaults, the 'Key Vault Administrator' role is required #. audit_azure_key_vault_private_endpoints () { print_function "audit_azure_key_vault_private_endpoints" check_message "Azure Key Vault Private Endpoints" command="az resource list --query \"[?type=='Microsoft.KeyVault/vaults'].name\" --output tsv" command_message "${command}" res_names=$( eval "${command}" 2> /dev/null ) if [ -z "${res_names}" ]; then info_message "No Key Vaults found" return fi for res_name in ${res_names}; do command="az resource list --name \"${res_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_groups=$( eval "${command}" ) for res_group in ${res_groups}; do check_azure_key_vault_value "${res_name}" "${res_group}" "properties.privateEndpointConnections" "ne" "" "" done done } ================================================ FILE: modules/azure/vaults/audit_azure_key_vault_public_network_access.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_key_vault_public_network_access # # Check Azure Key Vault Public Network Access # # 8.3.7 Ensure Public Network Access is Disabled # # Refer to Section(s) 8.3.7 Page(s) 447-50 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured # Audit account needs to have the 'Key Vault Reader' role # To do any changes to the key vaults, the 'Key Vault Administrator' role is required #. audit_azure_key_vault_public_network_access () { print_function "audit_azure_key_vault_public_network_access" check_message "Azure Key Vault Public Network Access" command="az resource list --query \"[?type=='Microsoft.KeyVault/vaults'].name\" --output tsv" command_message "${command}" res_names=$( eval "${command}" 2> /dev/null ) if [ -z "${res_names}" ]; then info_message "No Key Vaults found" return fi for res_name in ${res_names}; do command="az resource list --name \"${res_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_groups=$( eval "${command}" ) for res_group in ${res_groups}; do check_azure_key_vault_value "${res_name}" "${res_group}" "properties.publicNetworkAccess" "eq" "Disabled" "--public-network-access" done done } ================================================ FILE: modules/azure/vaults/audit_azure_key_vault_purge_protection.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_key_vault_purge_protection # # Check Azure Key Vault Purge Protection # # 8.3.5 Ensure that Purge Protection is enabled for all Key Vaults # # Refer to Section(s) 8.3.5 Page(s) 440-3 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured # Audit account needs to have the 'Key Vault Reader' role # To do any changes to the key vaults, the 'Key Vault Administrator' role is required #. audit_azure_key_vault_purge_protection () { print_function "audit_azure_key_vault_purge_protection" check_message "Azure Key Vault Purge Protection" command="az resource list --query \"[?type=='Microsoft.KeyVault/vaults'].name\" --output tsv" command_message "${command}" res_names=$( eval "${command}" 2> /dev/null ) if [ -z "${res_names}" ]; then info_message "No Key Vaults found" return fi for res_name in ${res_names}; do command="az resource list --name \"${res_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_groups=$( eval "${command}" ) for res_group in ${res_groups}; do command="az resource show --resource-group \"${res_group}\" --name \"${res_name}\" --resource-type \"Microsoft.KeyVault/vaults\" --query \"properties.enablePurgeProtection\" --output tsv" command_message "${command}" protection=$( eval "${command}" ) check_message "Azure Key Vault \"${res_name}\" purge protection" if [ "${protection}" = "true" ]; then inc_secure "Azure Key Vault \"${res_name}\" purge protection is enabled" else inc_insecure "Azure Key Vault \"${res_name}\" purge protection is not enabled" verbose_message "az resource update --resource-group ${res_group} --name ${res_name} --resource-type \"Microsoft.KeyVault/vaults\" --set properties.enablePurgeProtection=true" "fix" fi done done } ================================================ FILE: modules/azure/vaults/audit_azure_key_vault_rbac.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_key_vault_rbac # # Check Azure Key Vault RBAC # # 8.3.5 Ensure that Purge Protection is enabled for all Key Vaults # # Refer to Section(s) 8.3.5 Page(s) 440-3 CIS Microsoft Azure Foundations Benchmark v5.0.0 # # This requires the Azure CLI to be installed and configured # Audit account needs to have the 'Key Vault Reader' role # To do any changes to the key vaults, the 'Key Vault Administrator' role is required #. audit_azure_key_vault_rbac () { print_function "audit_azure_key_vault_rbac" check_message "Azure Key Vault RBAC" command="az resource list --query \"[?type=='Microsoft.KeyVault/vaults'].name\" --output tsv" command_message "${command}" res_names=$( eval "${command}" 2> /dev/null ) if [ -z "${res_names}" ]; then info_message "No Key Vaults found" return fi for res_name in ${res_names}; do command="az resource list --name \"${res_name}\" --query \"[].resourceGroup\" --output tsv" command_message "${command}" res_groups=$( eval "${command}" ) for res_group in ${res_groups}; do check_azure_key_vault_value "${res_name}" "${res_group}" "properties.enableRbacAuthorization" "eq" "true" "--enable-rbac-authorization" done done } ================================================ FILE: modules/azure/vaults/audit_azure_key_vault_secrets.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_key_vault_secrets # # Check Azure Key Vault Secrets # # 2.5 Ensure Azure Key Vaults are Used to Store Secrets # # Refer to Section(s) 2.5 Page(s) 238-42 CIS Microsoft Azure Compute Services Benchmark v2.0.0 # # This requires the Azure CLI to be installed and configured # Audit account needs to have the 'Key Vault Reader' role # To do any changes to the key vaults, the 'Key Vault Administrator' role is required #. audit_azure_key_vault_secrets () { print_function "audit_azure_key_vault_secrets" check_message "Azure Key Vault Secrets" command="az keyvault list --query \"[].id\" --output tsv" command_message "${command}" key_vaults=$( eval "${command}" 2> /dev/null ) if [ -z "${key_vaults}" ]; then insecure_message "No Key Vault Secrets found" else secure_message "Key Vault Secrets found" fi } ================================================ FILE: modules/azure/vaults/audit_azure_recovery_services_vaults.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_azure_recovery_services_vaults # # Check Azure Recovery Services Vaults # # 5.2.1 Ensure soft delete on Recovery Services vaults is Enabled # 5.2.2 Ensure immutability for Recovery Services vaults is Enabled # 5.2.3 Ensure backup data in Recovery Services vaults is encrypted using customer-managed keys (CMK) # 5.2.4 Ensure 'Use infrastructure encryption for this vault' is enabled on Recovery Services vaults # 5.2.5 Ensure public network access on Recovery Services vaults is Disabled # 5.2.6 Ensure 'Cross Region Restore' is set to 'Enabled' on Recovery Services vaults # 5.2.7 Ensure 'Cross Subscription Restore' is set to 'Disabled' or 'Permanently Disabled' on Recovery Services vaults # # Refer to Section(s) 2 Page(s) 25- CIS Microsoft Azure Storage Services Benchmark v1.0.0 # # This requires the Azure CLI to be installed and configured #. audit_azure_recovery_services_vaults () { print_function "audit_azure_recovery_services_vaults" check_message "Azure Recovery Services Vaults" immutability_state="Locked" retention_days="90" command="az backup vault list --query \"[].id\" --output tsv" command_message "${command}" vault_ids=$( eval "${command}" ) if [ -z "${vault_ids}" ]; then info_message "No Recovery Services Vaults found" return fi for vault_id in ${vault_ids}; do command="az backup vault show --id \"${vault_id}\" --query \"resourceGroup\" --output tsv" command_message "${command}" res_group=$( eval "${command}" ) command="az backup vault show --id \"${vault_id}\" --query \"name\" --output tsv" command_message "${command}" vault_name=$( eval "${command}" ) # 5.2.1 Ensure soft delete on Recovery Services vaults is Enabled check_azure_backup_vault_value "Soft Delete" "${vault_name}" "${res_group}" "properties.encryption.keyUri" "ne" "" "" # 5.2.3 Ensure backup data in Recovery Services vaults is encrypted using customer-managed keys (CMK) check_azure_backup_vault_value "Customer Managed Keys" "${vault_name}" "${res_group}" "properties.softDeleteFeatureState" "eq" "Enabled" "properties.softDeleteFeatureState" # 5.2.4 Ensure 'Use infrastructure encryption for this vault' is enabled on Recovery Services vaults check_azure_backup_vault_value "Infrastructure Encryption" "${vault_name}" "${res_group}" "properties.infrastructureEncryptionEnabled" "eq" "true" "--infrastructure-encryption-enabled" # 5.2.6 Ensure 'Cross Region Restore' is set to 'Enabled' on Recovery Services vaults check_azure_backup_vault_value "Cross Region Restore" "${vault_name}" "${res_group}" "properties.crossRegionRestoreFlag" "eq" "Enabled" "properties.crossRegionRestoreFlag" # 5.2.7 Ensure 'Cross Subscription Restore' is set to 'Disabled' or 'Permanently Disabled' on Recovery Services vaults check_azure_backup_vault_value "Cross Subscription Restore" "${vault_name}" "${res_group}" "properties.crossSubscriptionRestoreFlag" "eq" "Disabled" "properties.crossSubscriptionRestoreFlag" # 5.2.5 Ensure public network access on Recovery Services vaults is Disabled check_azure_backup_vault_value "Public Network Access" "${vault_name}" "${res_group}" "properties.publicNetworkAccess" "eq" "Disabled" "properties.publicNetworkAccess" # 5.2.2 Ensure immutability for Recovery Services vaults is Enabled command="az backup policy list --vault-name \"${vault_name}\" --resource-group \"${res_group}\" --query \"[].name\" --output tsv" command_message "${command}" policy_names=$( eval "${command}" ) for policy_name in ${policy_names}; do check_azure_backup_policy_value "Immutability Settings" "${policy_name}" "${vault_name}" "${res_group}" "immutabilitySettings" "ne" "" "" check_azure_backup_policy_value "Immutability State" "${policy_name}" "${vault_name}" "${res_group}" "immutabilitySettings.state" "eq" "${immutability_state}" "--immutability-state" check_azure_backup_policy_value "Immutability Retention Duration" "${policy_name}" "${vault_name}" "${res_group}" "immutabilitySettings.retentionDurationInDays" "eq" "${retention_days}" "--retention-days" done done } ================================================ FILE: modules/bluetooth/audit_bluetooth.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_bluetooth # # Check bluetooth # # Refer to Section(s) 2.1.1 Page(s) 8-11 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.1.1-3 Page(s) 21-5 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.3.3.11,2.4.4 Page(s) 118-20,37-9 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 # Refer to Section(s) 3.1.3 Page(s) 361-3 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_bluetooth () { print_function "audit_bluetooth" string="Bluetooth services and file sharing" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_int "/Library/Preferences/com.apple.Bluetooth" "ControllerPowerState" "0" check_osx_defaults_int "/Library/Preferences/com.apple.Bluetooth" "PANServices" "0" check_osx_defaults_bool "/Library/Preferences/com.apple.Bluetooth" "BluetoothSystemWakeEnable" "0" backup_file="bluetooth_discover" if [ "${audit_mode}" != 2 ]; then if [ "${os_version}" -ge 14 ]; then command="find /Users -maxdepth 1 -type d |grep -vE \"localized|Shared\" |cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.Bluetooth" "PrefKeyServicesEnabled" "0" "bool" "${user_name}" check_osx_defaults_user "com.apple.controlcenter.plist" "Bluetooth" "18" "int" "${user_name}" done fi command="system_profiler SPBluetoothDataType | grep -i power | cut -f2 -d: | sed \"s/ //g\"" command_message "${command}" bt_check=$( eval "${command}" ) if [ ! "${bt_check}" = "Off" ]; then command="system_profiler SPBluetoothDataType | grep -i discoverable | cut -f2 -d: | sed \"s/ //g\"" command_message "${command}" bt_check=$( eval "${command}" ) if [ "${bt_check}" = "Off" ]; then inc_secure "Bluetooth is not discoverable" else inc_insecure "Bluetooth is discoverable" fi else inc_secure "Bluetooth is turned off" fi command="defaults read com.apple.systemuiserver menuExtras 2>&1 |grep Bluetooth.menu |sed \"s/[ ,\\\",\\\,]//g\"" command_message "${command}" defaults_check=$( eval "${command}" ) if [ "${defaults_check}" = "/System/Library/CoreServices/MenuExtras/Bluetooth.menu" ]; then inc_secure "Bluetooth status menu is enabled" else inc_insecure "Bluetooth status menu is not enabled" fi fi else if [ "${os_name}" = "Linux" ]; then check_linux_service "bluez" "off" check_linux_package "uninstall" "bluez" else na_message "${string}" fi fi } ================================================ FILE: modules/boot/audit_boot_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_boot_server # # Turn off boot services #. audit_boot_server () { print_function "audit_boot_server" audit_rarp audit_bootparams audit_tftp_server audit_dhcp_server } ================================================ FILE: modules/boot/audit_bootparams.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_bootparams # # Turn off bootparamd #. audit_bootparams () { print_function "audit_bootparams" string="Bootparams Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" -gt 9 ]; then check_sunos_service "svc:/network/rpc/bootparams:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "bootparamd" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/boot/audit_grub_security.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_grub_security # # Check GRUB security # # Refer to Section(s) 1.5.3 Page(s) 47-8 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.4.1 Page(s) 57 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 1.4.1 Page(s) 52 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.4.1-2 Page(s) 160-4 CIS Ubuntu 24.04 Benchmark v1.0.0 # Refer to Section(s) 3.1 Page(s) 31-2 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.4.1 Page(s) 50 CIS Amazon Linux Benchmark v2.0.0 #. audit_grub_security () { print_function "audit_grub_security" string="Grub Menu Security" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${os_name}" = "Linux" ]; then for check_file in /etc/grub.conf /boot/grub/grub.cfg /boot/grub/menu.list; do check_file_perms "${check_file}" "0600" "root" "root" done check_file_value "is" "/boot/grub/grub.cfg" "set superusers" "eq" "root" "hash" check_file_value "is" "/boot/grub/grub.cfg" "password_pbkdf2" "space" "root" "hash" check_file_value "is" "/boot/grub/grub.cfg" "selinux" "eq" "1" "hash" check_file_value "is" "/boot/grub/grub.cfg" "enforcing" "eq" "1" "hash" check_file_value "is" "/etc/default/grub" "audit" "eq" "1" "hash" fi # if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then # check_file="/boot/grub/menu.lst" # grub_check=`cat ${check_file} |grep "^password --md5" |awk '{print $1}'` # if [ "$grub_check" != "password" ]; then # if [ "${audit_mode}" = 1 ]; then # inc_insecure "Grub password not set" # fi # This code needs work # if [ "${audit_mode}" = 0 ]; then # echo "Setting: Grub password" # if [ ! -f "${log_file}" ]; then # echo "Saving: File ${check_file} to ${log_file}" # find ${check_file} | cpio -pdm ${work_dir} 2> /dev/null # fi # echo -n "Enter password: " # read $password_string # password_string=`htpasswd -nb test $password_string |cut -f2 -d:` # echo "password --md5 $password_string" >> ${check_file} # chmod 600 ${check_file} # lock_check=`cat ${check_file} |grep lock` # if [ "$lock_check" != "lock" ]; then # cat ${check_file} |sed 's,Solaris failsafe,Solaris failsafe Lock,g' >> ${temp_file} # cp ${temp_file} ${check_file} # rm ${temp_file} # fi # fi # else # if [ "${audit_mode}" = 1 ]; then # inc_secure "Set-UID not restricted on user mounted devices" # fi # if [ "${audit_mode}" = 2 ]; then # restore_file="${restore_dir}${check_file}" # if [ -f "${restore_file}" ]; then # echo "Restoring: ${restore_file} to ${check_file}" # cp -p ${restore_file} ${check_file} # if [ "${os_version}" = "10" ]; then # pkgchk -f -n -p ${check_file} 2> /dev/null # else # pkg fix `pkg search ${check_file} |grep pkg |awk '{print $4}'` # fi # fi # fi # fi # fi else na_message "${string}" fi } ================================================ FILE: modules/core/audit_core_dumps.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2043 # audit_core_dumps # # Check core dumps # # Refer to Section(s) 1.6.1 Page(s) 44-5 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.6.1 Page(s) 50-1 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.5.1 Page(s) 47 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.4.1 Page(s) 57 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 4.1 Page(s) 35-6 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.5.1 Page(s) 56-7 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.5.3 Page(s) 175-8 CIS Ubuntu 24.04 Benchmark v1.0.0 # Refer to Section(s) 4.1 Page(s) 16 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 3.1 Page(s) 25-6 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 3.2 Page(s) 61-2 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 1.5.1 Page(s) 53 CIS Amazon Linux Benchmark v2.0.0 #. audit_core_dumps () { print_function "audit_core_dumps" string="Core Dumps" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" != "6" ]; then cores_dir="/var/cores" check_file="/etc/coreadm.conf" command="coreadm | head -1 | awk '{print \$5}' | grep \"/var/cores\"" command_message "${command}" cores_check=$( eval "${command}" ) if [ -z "${cores_check}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Cores are not restricted to a private directory" else if [ "${audit_mode}" = 0 ]; then verbose_message "Making sure restricted to a private directory" "set" if [ -f "${check_file}" ]; then verbose_message "File \"${check_file}\" to \"${work_dir}${check_file}\"" "save" find "${check_file}" | cpio -pdm "${work_dir}" 2> /dev/null else touch "${check_file}" find "${check_file}" | cpio -pdm "${work_dir}" 2> /dev/null if [ -f "${check_file}" ]; then rm "${check_file}" fi log_file="${work_dir}/${check_file}" coreadm | sed -e 's/^ *//g' | sed 's/ /_/g' | sed 's/:_/:/g' | awk -F: '{ print $1" "$2 }' | while read -r option value; do if [ "$option" = "global_core_file_pattern" ]; then echo "COREADM_GLOB_PATTERN=${value}" > "${log_file}" fi if [ "$option" = "global_core_file_content" ]; then echo "COREADM_GLOB_CONTENT=${value}" >> "${log_file}" fi if [ "$option" = "init_core_file_pattern" ]; then echo "COREADM_INIT_PATTERN=${value}" >> "${log_file}" fi if [ "$option" = "init_core_file_content" ]; then echo "COREADM_INIT_CONTENT=${value}" >> "${log_file}" fi if [ "$option" = "global_core_dumps" ]; then if [ "${value}" = "enabled" ]; then value="yes" else value="no" fi echo "COREADM_GLOB_ENABLED=${value}" >> "${log_file}" fi if [ "$option" = "per-process_core_dumps" ]; then if [ "${value}" = "enabled" ]; then value="yes" else value="no" fi echo "COREADM_PROC_ENABLED=${value}" >> "${log_file}" fi if [ "$option" = "global_setid_core_dumps" ]; then if [ "${value}" = "enabled" ]; then value="yes" else value="no" fi echo "COREADM_GLOB_SETID_ENABLED=${value}" >> "${log_file}" fi if [ "$option" = "per-process_setid_core_dumps" ]; then if [ "${value}" = "enabled" ]; then value="yes" else value="no" fi echo "COREADM_PROC_SETID_ENABLED=${value}" >> "${log_file}" fi if [ "$option" = "global_core_dump_logging" ]; then if [ "${value}" = "enabled" ]; then value="yes" else value="no" fi echo "COREADM_GLOB_LOG_ENABLED=${value}" >> "${log_file}" fi done fi coreadm -g /var/cores/core_%n_%f_%u_%g_%t_%p -e log -e global -e global-setid -d process -d proc-setid fi if [ ! -d "${cores_dir}" ]; then mkdir "${cores_dir}" chmod 700 "${cores_dir}" chown root:root "${cores_dir}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Cores are restricted to a private directory" fi fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}${check_file}" restore_file "${check_file}" "${restore_dir}" if [ -f "${restore_file}" ]; then coreadm -u fi fi fi fi if [ "${os_name}" = "Linux" ]; then check_message "Core Dumps" check_linux_service "kdump" "off" check_append_file "/etc/security/limits.conf" "* hard core 0" "hash" check_file_value "is" "/etc/sysctl.conf" "fs.suid_dumpable" "eq" "0" "hash" fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/sysctl.conf" "kern.coredump" "eq" "0" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/core/audit_core_limit.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_core_limit # # Check core dump limits # # Refer to Section(s) 2.10 Page(s) 34-35 CIS Apple OS X 10.8 Benchmark v1.0.0 #. audit_core_limit () { print_function "audit_core_limit" string="Core dump limits" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then log_file="corelimit" backup_file="${work_dir}/${log_file}" current_value=$( launchctl limit core | awk '{print $3}' ) if [ "${audit_mode}" != 2 ]; then if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_core_limit_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"launchctl limit core | awk '{print \$3}'\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"launchctl limit core 0\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${current_value}" != "0" ]; then if [ ! "${audit_mode}" = 0 ]; then inc_insecure "Core dumps unlimited" fix_message "launchctl limit core 0" fi if [ "${audit_mode}" = 0 ]; then set_message "Core dump limits" echo "${current_value}" > "${log_file}" launchctl limit core 0 fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Core dump limits exist" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then previous_value=$( cat "${restore_file}" ) if [ "${current_value}" != "${previous_value}" ]; then restore_message "Core limit to \"${previous_value}\"" launchctl limit core unlimited fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/core/audit_core_storage.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2196 # audit_core_storage # # Ensure all user core storage volumes are encrypted # # Refer to Section(s) 5.3.2 Page(s) 339-42 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_core_storage () { print_function "audit_core_storage" string="Core Storage Volumes" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${audit_mode}" != 2 ]; then command="diskutil cs list | egrep -v \"Snapshot|Not Mounted|Sealed|Capacity\" | grep -A1 \"/\" | grep -v \"\-\" | sed \"s/\|//g\" | sed \"s/ //g\" | grep -B1 \"FileVault:No\" | grep \"MountPoint\" | cut -f2 -d:" command_message "${command}" insecure_vols=$( eval "${command}" ) for volume in ${insecure_vols}; do inc_insecure "Core Storage Volume \"${volume}\" is not encrypted" done command="diskutil cs list | egrep -v \"Snapshot|Not Mounted|Sealed|Capacity\" | grep -A1 \"/\" | grep -v \"\-\" | sed \"s/\|//g\" | sed \"s/ //g\" | grep -B1 \"FileVault:Yes\" | grep \"MountPoint\" | cut -f2 -d:" command_message "${command}" secure_vols=$( eval "${command}" ) for volume in ${secure_vols}; do inc_secure "Core Storage Volume \"${volume}\" is encrypted" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/cron/audit_cron.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cron # # Check cron # # Refer to Section(s) 6.1.1 Page(s) 138-9 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 6.1.1 Page(s) 121-2 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 9.1.1 Page(s) 114-5 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 5.1.1 Page(s) 192 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 5.1.1 Page(s) 204 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.4.1.1 Page(s) 329-30 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_cron () { print_function "audit_cron" string="Cron Daemon" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_linux_service "crond" "on" if [ "${anacron_enable}" = "yes" ]; then check_linux_service "anacron" "on" fi else na_message "${string}" fi } ================================================ FILE: modules/cron/audit_cron_allow.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cron_allow # # Check cron allow # # Refer to Section(s) 6.1.10-1 Page(s) 125-7 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.1.10-1 Page(s) 128-30 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.1.10-1 Page(s) 145-7 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.1.8 Page(s) 120 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 7.4 Page(s) 25 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.11.8-10,2.12.13-4 Page(s) 196-8,217-8 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 6.13 Page(s) 56-7 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.9 Page(s) 93-4 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 2.4.1.8-2.1 Page(s) 343-51 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_cron_allow () { print_function "audit_cron_allow" string="At/Cron Authorized Users" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "FreeBSD" ]; then cron_base_dir="/var/cron" at_base_dir="/var/at" cron_group="${wheel_group}" check_file="/etc/crontab" check_file_perms "${check_file}" "0640" "root" "${cron_group}" else if [ "${os_name}" = "AIX" ]; then cron_base_dir="/var/adm/cron" at_base_dir="/var/adm/cron" cron_group="cron" else if [ "${os_name}" = "SunOS" ] && [ "${os_version}" = "11" ] || [ "${os_name}" = "Linux" ]; then cron_base_dir="/etc/cron.d" at_base_dir="/etc/cron.d" cron_group="root" else cron_base_dir="/etc" at_base_dir="/etc" cron_group="root" fi fi fi check_file_exists "${cron_base_dir}/cron.deny" "no" check_file_exists "${at_base_dir}/at.deny" "no" check_file_exists "${cron_base_dir}/cron.allow" "yes" check_file_perms "${cron_base_dir}/cron.allow" "0400" "root" "${cron_group}" check_file_exists "${at_base_dir}/at.allow" "yes" check_file_perms "${at_base_dir}/at.allow" "0400" "root" "${cron_group}" if [ "${audit_mode}" = 0 ]; then for dir_name in var/spool/cron var/spool/cron/crontabs ; do if [ -d "${dir_name}" ]; then command="find \"${dir_name}\" -maxdepth 1 -type f -exec basename {} \;" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do command="grep \"^${user_name}\" < /etc/passwd | cut -f 1 -d:" command_message "${command}" check_id=$( eval "${command}" ) if [ "${check_id}" = "${user_name}" ]; then echo "${user_name}" >> "${cron_file}" echo "${user_name}" >> "${at_file}" fi done fi done for dir_name in /etc/cron.d /etc/cron.hourly /etc/cron.daily /etc/cron.yearly; do if [ -d "${dir_name}" ]; then command="find \"${dir_name}\" -type f -not -user root -printf '%u\n' | sort -u" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do command="grep \"${user_name}\" \"${check_file}\"" command_message "${command}" user_check=$( eval "${command}" ) if [ "${user_check}" != "${user_name}" ]; then echo "${user_name}" >> "${at_base_dir}/at.allow" echo "${user_name}" >> "${cron_base_dir}/cron.allow" fi done fi done fi check_file_perms "${check_file}" "0640" "root" "root" check_file="/etc/at.allow" check_file_exists "${check_file}" "yes" if [ "${audit_mode}" = 0 ]; then if [ "${os_name}" = "SunOS" ]; then f_check=$( wc -l "${check_file}" | awk '{print $1}' | sed "s/ //g" ) if [ "$f_check" = "0" ]; then dir_name="/var/spool/cron/atjobs" if [ -d "${dir_name}" ]; then command="ls ${dir_name}" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do command="grep \"${user_name}\" \"${check_file}\"" command_message "${command}" user_check=$( eval "${command}" ) if [ "${user_check}" != "${user_name}" ]; then echo "${user_name}" >> "${check_file}" fi done fi fi fi if [ "${os_name}" = "Linux" ]; then f_check=$( wc -l "${check_file}" | awk '{ print $1 }' | sed "s/ //g" ) if [ "$f_check" = "0" ]; then dir_name="/var/spool/at/spool" if [ -d "${dir_name}" ]; then command="ls /var/spool/at/spool" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do command="grep \"${user_name}\" \"${check_file}\"" command_message "${command}" user_check=$( eval "${command}" ) if [ "${user_check}" != "${user_name}" ]; then echo "${user_name}" >> "${check_file}" fi done fi fi fi fi command="check_file_perms \"${check_file}\" \"0640\" \"root\" \"root\"" command_message "${command}" eval "${command}" if [ "${os_name}" = "Linux" ]; then for dir_name in /etc/cron.d /etc/cron.hourly /etc/cron.daily /etc/cron.yearly; do command="check_file_perms \"${dir_name}\" \"0700\" \"root\" \"root\"" command_message "${command}" eval "${command}" done for file_name in /etc/crontab /etc/anacrontab /etc/cron.allow /etc/at.allow; do check_file_perms "${check_file}" "0600" "root" "root" done fi else na_message "${string}" fi } ================================================ FILE: modules/cron/audit_cron_logging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cron_logging # # Check cron logging # # Refer to Section(s) 4.7 Page(s) 71 CIS Solaris 10 Benchmark v5.1.0 #. audit_cron_logging () { print_function "audit_cron_logging" string="Cron Logging" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file_value "is" "/etc/default/cron" "CRONLOG" "eq" "YES" "hash" check_file_perms "/var/cron/log" "0640" "root" "root" fi else na_message "${string}" fi } ================================================ FILE: modules/cron/audit_cron_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cron_perms # # Check cron permissions # # Refer to Section(s) 6.1.2-9 Page(s) 119-125 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.1.2-9 Page(s) 138-9 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 6.1.2-9 Page(s) 122-8 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.1.2-9 Page(s) 210-7 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 9.1.2-8 Page(s) 115-9 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 5.1.2-9 Page(s) 193-200 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 5.1.2-8 Page(s) 205-12 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.4.1.2-7 Page(s) 331-42 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_cron_perms () { print_function "audit_cron_perms" string="Cron Permissions" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for check_file in /etc/crontab /var/spool/cron /etc/cron.daily /etc/cron.d \ /etc/cron.weekly /etc/cron.monthly /etc/cron.hourly /etc/anacrontab; do check_file_perms "${check_file}" "0700" "root" "root" done else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_account_lockout.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_account_lockout # # Check Account Lockout # # Refer to Section(s) 5.18 Page(s) 66-67 CIS Apple OS X 10.8 Benchmark v1.0.0 #. audit_account_lockout () { print_function "audit_account_lockout" string="Account Lockout" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_pwpolicy "maxFailedLoginAttempts" "3" else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_account_switching.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_account_switching # # Disabling the administrator's and/or user's ability to log into another user's active and # locked session prevents unauthorized persons from viewing potentially sensitive and/or # personal information. # # Refer to Section(s) 5.7 Page(s) 350-1 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_account_switching () { print_function "audit_account_switching" string="Administrator Account Login to Another User Session" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_account_switching_${ansible_counter}" if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${audit_mode}" != 2 ]; then correct_value="0" get_command="sudo /usr/bin/security authorizationdb read system.login.screensaver 2>&1 | /usr/bin/grep -c 'use-login-window-ui'" set_command="sudo /usr/bin/security authorizationdb write system.login.screensaver use-login-window-ui" current_value=$( eval "${get_command}" ) if [ "${current_value}" = "${correct_value}" ]; then inc_secure "Administrator Account Login to Another User Session is set to \"${correct_value}\"" else inc_insecure "Administrator Account Login to Another User Session is not set to \"${correct_value}\"" fi if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} != 0" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" else lock_command="${set_command}" lock_message="Disable ${string}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_ad_tracking.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ad_tracking # # Organizations should manage advertising settings on computers rather than allow users # to configure the settings. # # Refer to Section(s) 2.6.4 Page(s) 170- CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_ad_tracking () { print_function "audit_ad_tracking" string="Ad Tracking" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.AdLib.plist" "allowApplePersonalizedAdvertising" "0" "bool" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_air_drop.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_air_drop # # AirDrop can allow malicious files to be downloaded from unknown sources. Contacts # Only limits may expose personal information to devices in the same area. # # Refer to Section(s) 2.3.1.1 Page(s) 72-6 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_air_drop () { print_function "audit_air_drop" string="Air Drop" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.NetworkBrowser" "DisableAirDrop" "1" "bool" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_air_play.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_air_play # # AirDrop can allow malicious files to be downloaded from unknown sources. Contacts # Only limits may expose personal information to devices in the same area. # # Refer to Section(s) 2.3.1.2 Page(s) 77-80 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_air_play () { print_function "audit_air_play" string="Air Play Receiver" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.controlcenter.plist" "AirplayRecieverEnabled" "0" "bool" "currentHost" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_amfi.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_amfi # # Apple Mobile File Integrity validates that application code is validated. # # Refer to Section(s) 5.1.3 Page(s) 303-4 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_amfi () { print_function "audit_amfi" string="Apple Mobile File Integrity" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1012 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi get_command="sh -c \"sudo nvram -p > /dev/null 2>&1 | grep -c amfi | sed 's/ //g'" set_command="sudo /usr/sbin/nvram boot-args=\\\"\\\"" if [ "${audit_mode}" != 2 ]; then command="sudo nvram -p > /dev/null 2>&1 | grep -c amfi | sed 's/ //g'" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" = "0" ]; then inc_secure "Apple Mobile File Integrity is not \"disabled\"" else inc_insecure "Apple Mobile File Integrity is set to \"${check_value}\"" fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_amfi_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}'\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} != 0" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" else lock_command="sudo /usr/sbin/nvram boot-args=\"\"" lock_message="Enable ${string}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_apfs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2196 # audit_apfs # # Ensure all user storage APFS volumes are encrypted # # Refer to Section(s) 5.3.1 Page(s) 335-8 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_apfs () { print_function "audit_apfs" string="APFS Volumes" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${audit_mode}" != 2 ]; then command="diskutil ap list | grep -Ev \"Snapshot|Not Mounted|Sealed|Capacity\" | grep -A1 \"/\" | grep -v \"\-\" | sed \"s/\|//g\" | sed \"s/ //g\" | grep -B1 \"FileVault:No\" | grep \"MountPoint\" | cut -f2 -d:" command_message "${command}" insecure_vols=$( eval "${command}" ) for volume in ${insecure_vols}; do inc_insecure "APFS Volume \"${volume}\" is not encrypted" done command="diskutil ap list | grep -Ev \"Snapshot|Not Mounted|Sealed|Capacity\" | grep -A1 \"/\" | grep -v \"\-\" | sed \"s/\|//g\" | sed \"s/ //g\" | grep -B1 \"FileVault:Yes\" | grep \"MountPoint\" | cut -f2 -d:" command_message "${command}" secure_vols=$( eval "${command}" ) for volume in ${secure_vols}; do inc_secure "APFS Volume \"${volume}\" is encrypted" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_app_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_app_perms # # Check Application Permissions # # Refer to Section(s) 5.1.2 Page(s) 109 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 5.1.5-6 Page(s) 307-10 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_app_perms () { print_function "audit_app_perms" string="Application Permissions" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then OFS=$IFS IFS=$(printf '\n+'); IFS=${IFS%?} for check_dir in Applications System; do test_dirs=$( find /${check_dir} -maxdepth 1 -type d ) for test_dir in ${test_dirs}; do check_file_perms "${test_dir}" "0755" "" "" done done IFS=$OFS fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_asl.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_asl # # Check how long system logs are being kept for # # Refer to Section(s) 3.1.1-3,3.5 Page(s) 85-60,94-5 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 3.3 Page(s) 276-7 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_asl () { print_function "audit_asl" string="System Logging" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_append_file "/etc/asl.conf" "> system.log mode=0640 format=bsd rotate=utc compress file_max=5M ttl=90" "hash" check_append_file "/etc/asl.conf" "> appfirewall.log mode=0640 format=bsd rotate=utc compress file_max=5M ttl=90" "hash" check_append_file "/etc/asl/com.apple.authd" "* file /var/log/authd.log mode=0640 format=bsd rotate=utc compress file_max=5M ttl=90" "hash" check_append_file "/etc/asl/com.apple.install" "* file /var/log/install.log mode=0640 format=bsd rotate=utc compress file_max=5M ttl=365" "hash" else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_asset_cache.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_asset_cache # # The main use case for Mac computers is as mobile user endpoints. P2P sharing # services should not be enabled on laptops that are using untrusted networks. Content # Caching can allow a computer to be a server for local nodes on an untrusted network. # While there are certainly logical controls that could be used to mitigate risk, they add to # the management complexity. Since the value of the service is in specific use cases, # # Refer to Section(s) 2.3.3.9 Page(s) 111-3 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_asset_cache () { print_function "audit_asset_cache" string="Asset Cache Activation" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1013 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then get_command="sudo AssetCacheManagerUtil status 2>&1 | grep Activated | awk '{print \$2}' | grep -ci false | sed 's/ //g'" set_command="sudo /usr/bin/AssetCacheManagerUtil deactivate" check_value=$( eval "${get_command}" ) if [ "${check_value}" = "0" ]; then inc_secure "Content Caching is not activated" else inc_insecure "Content Caching is activated" fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_asset_cache_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} != 0" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" else lock_command="${set_command}" lock_message="Disable ${string}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_auto_login.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_auto_login # # Disabling automatic login decreases the likelihood of an unauthorized person gaining # access to a system. # # Refer to Section(s) 5.7 Page(s) 53-54 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 5.8,6.1.1 Page(s) 152-3 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.12.3 Page(s) 248-50 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_auto_login() { print_function "audit_auto_login" string="Autologin" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_bool "/Library/Preferences/.GlobalPreferences" "com.apple.userspref.DisableAutoLogin" "yes" if [ ! "${audit_mode}" != 2 ]; then get_command="defaults read /Library/Preferences/com.apple.loginwindow | grep -c autoLoginUser | sed 's/ //g'" set_command="sudo /usr/bin/defaults delete /Library/Preferences/com.apple.loginwindow autoLoginUser" defaults_check=$( eval "${get_command}" ) if [ "${defaults_check}" = "0" ]; then inc_insecure "${string} Disabled" else inc_secure "${string} Enabled" fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_auto_login_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} != 0" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" else lock_command="${set_command}" lock_message="Disable ${string}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_auto_logout.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_auto_logout # # Check AutoLogout # # Refer to Section(s) 5.11 Page(s) 57-58 CIS Apple OS X 10.8 Benchmark v1.0.0 #. audit_auto_logout () { print_function "audit_auto_logout" string="Autologout" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_int "/Library/Preferences/.GlobalPreferences" "com.apple.autologout.AutoLogOutDelay" "0" else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_bonjour_advertising.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2028 # audit_bonjour_advertising # # Refer to Section(s) 3.4-7 Page(s) 39-40 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.4.14.14 Page(s) 62-3 CIS Apple OS X 10.5 Benchmark v1.1.0 # Refer to Section(s) 4.1 Page(s) 96-7 CIS Apple OS X 10.5 Benchmark v1.1.0 # Refer to Section(s) 4.1 Page(s) 290-1 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_bonjour_advertising() { print_function "audit_bonjour_advertising" string="Bonjour Multicast Advertising" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_file="/System/Library/LaunchDaemons/com.apple.mDNSResponder.plist" if [ "${long_os_version}" -ge 1014 ]; then check_osx_defaults_bool "/Library/Preferences/com.apple.mDNSResponder.plist" "NoMulticastAdvertisements" "1" else temp_file="${temp_dir}/mdnsmcast" if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else get_command="cat ${check_file} |grep NoMulticastAdvertisements" set_command="sed 's,mDNSResponder,&X -NoMulticastAdvertisements,g' < ${check_file} | tr X '\n' > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" multicast_test=$( grep -c "NoMulticastAdvertisements" "${check_file}" ) if [ -n "${ansible_mode}" ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_bonjour_advertising_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ -n "$multicast_test" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Bonjour Multicast Advertising enabled" fix_message "${set_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Bonjour Multicast Advertising disabled" lock_command="${set_command}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Bonjour Multicast Advertising disabled" fi fi fi fi if [ "$osx_mdns_enable" != "yes" ]; then check_launchctl_service "com.apple.mDNSResponder" "off" check_launchctl_service "com.apple.mDNSResponderHelper" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_cd_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cd_sharing # # Check CD sharing # # Refer to Section(s) 2.4.6 Page(s) 22 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.4.6 Page(s) 44 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.3.3.1 Page(s) 90-1 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_cd_sharing () { print_function "audit_cd_sharing" string="DVD/CD Sharing" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then check_launchctl_service "com.apple.ODSAgent" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_file_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_file_sharing # # Refer to Section 2.4.8 Page(s) 23-4 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section 2.4.8,6.1.4 Page(s) 46-7,158-9 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section 2.3.3.3 Page(s) 95-7 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_file_sharing () { print_function "audit_file_sharing" string="File Sharing" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_bool "/Library/Preferences/SystemConfiguration/com.apple.smb.server" "AllowGuestAccess" "no" check_launchctl_service "com.apple.AppleFileServer" "off" check_launchctl_service "nmbd" "off" check_launchctl_service "smbd" "off" else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_file_vault.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_file_vault # # FileVault secures a system's data by automatically encrypting its boot volume and # requiring a password or recovery key to access it. # # Refer to Section 2.6.1 Page(s) 28 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section 2.6.5 Page(s) 177-80 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_file_vault () { print_function "audit_file_vault" string="File Vault" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then actual_value=$( diskutil cs list ) if [ "${actual_value}" = "No CoreStorage logical volume groups found" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "File Vault is not enabled" fi if [ "${audit_mode}" = 1 ] || [ "${audit_mode}" = 0 ]; then verbose_message "Open System Preferences" "fix" verbose_message "Select Security & Privacy" "fix" verbose_message "Select FileVault" "fix" verbose_message "Select Turn on FileVault" "fix" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "File Vault is enabled" fi fi else verbose_message "Open System Preferences" "fix" verbose_message "Select Security & Privacy" "fix" verbose_message "Select FileVault" "fix" verbose_message "Select Turn on FileVault" "fix" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_gate_keeper.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_gate_keeper # # Gatekeeper is Apple’s application that utilizes allowlisting to restrict downloaded # applications from launching. It functions as a control to limit applications from unverified # sources from running without authorization. In an update to Gatekeeper in macOS 13 # Ventura, Gatekeeper checks every application on every launch, not just quarantined apps. # # Refer to Section 2.5.1 Page(s) 26-27 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section 2.6.2 Page(s) 55 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section 2.6.5 Page(s) 174-6 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_gate_keeper () { print_function "audit_gate_keeper" string="Gatekeeper" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi log_file="gatekeeper.log" if [ "${audit_mode}" != 2 ]; then actual_value=$( sudo spctl --status | awk '{print $2}' | sed 's/d$//g' ) if [ "${actual_value}" = "disable" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Gatekeeper is not enabled" fi if [ "${audit_mode}" = 0 ]; then set_message "Gatekeeper to enabled" echo "${actual_value}" > "${work_dir}/${log_file}" sudo spctl --master-enable fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Gatekeeper is enabled" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then restore_value=$( cat "${restore_file}" ) if [ "${restore_value}" != "${actual_value}" ]; then restore_message "Gatekeeper to \"${restore_value}\"" eval "sudo spctl --master-${restore_value}" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_guest_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_guest_sharing # # Not allowing guests to connect to shared folders mitigates the risk of an untrusted user # doing basic reconnaissance and possibly using privilege escalation attacks to take # control of the system. # # Refer to Section(s) 6.1.4 Page(s) 75-6 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.12.2,5.9 Page(s) 246-7,355-6 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_guest_sharing () { print_function "audit_guest_sharing" string="Guest account file sharing" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_bool "/Library/Preferences/com.apple.AppleFileServer" "guestAccess" "no" check_osx_defaults_bool "/Library/Preferences/SystemConfiguration/com.apple.smb.server" "AllowGuestAccess" "no" if [ "${long_os_version}" -ge 1014 ]; then check_sysadminctl "smbGuestAccess" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_icloud_drive.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_icloud_drive # # Organizations should review third party storage solutions pertaining to existing data # confidentiality and integrity requirements. # # Refer to Section(s) 2.1.1.2 Page(s) 45-8 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_icloud_drive () { print_function "audit_icloud_drive" string="iCloud Drive" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 |grep -vE \"localized|Shared\" |cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do for dir_name in Documents Desktop; do if [ -f "/Users/${user_name}/Library/Mobile\ Documents/com~apple~CloudDocs/${dir_name}" ]; then command="sudo -u \"${user_name}\" sh -c \"ls -l /Users/${user_name}/Library/Mobile\ Documents/com~apple~CloudDocs/${dir_name}/\" | grep -c total | sed \"s/ //g\"" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" = "0" ]; then inc_secure "Documents in \"${dir_name}\" for \"${user_name}\" are not syncing " else inc_insecure "Documents in \"${dir_name}\" for \"${user_name}\" are syncing " fi fi done done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_infrared_remote.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_infrared_remote # # Check Infrared Remote # # Refer to Section(s) 1.4.13.7 Page(s) 48-9 CIS Apple OS X 10.6 Benchmark v1.0.0 # Refer to Section(s) 2.9 Page(s) 79-80 CIS Apple OS X 10.12 Benchmark v1.0.0 # # Refer to http://support.apple.com/kb/PH11060 #. audit_infrared_remote () { print_function "audit_infrared_remote" string="Apple Remote Activation" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_bool "/Library/Preferences/com.apple.driver.AppleIRController" "DeviceEnabled" "no" else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_internet_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_internet_sharing # # Check Internet Sharing # # Refer to Section(s) 2.4.2 Page(s) 17-18 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.3.3.8 Page(s) 108-10 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_internet_sharing () { print_function "audit_internet_sharing" string="Internet Sharing" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_dict "/Library/Preferences/SystemConfiguration/com.apple.nat" "NAT" "Enabled" "dict" "0" "int" check_launchctl_service "com.apple.InternetSharing" "off" else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_java.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_java # # Check Java # # Refer to Section 2.11 Page(s) 82 CIS Apple OS X 10.8 Benchmark v1.0.0 #. audit_java () { print_function "audit_java" string="Java" check_message "${string}" minimum_value=7 if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then java_bin=$( command -v java ) if [ -n "$java_bin" ]; then verbose_message "Java version" "check" command="java -version 2>&1 | awk -F '\"' '/version/ {print \$2}' | cut -f1 -d." command_message "${command}" version_value=$( eval "${command}" ) if [ -n "${version_value}" ]; then if [ "${version_value}" -ge "${minimum_value}" ]; then inc_secure "Java version is greater than \"${minimum_value}\"" else inc_insecure "Java version is less than \"${minimum_value}\"" fi fi inc_secure "Java not installed" fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_keychain_lock.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_keychain_lock # # Check keychain lock # # Refer to Section(s) 5.2 Page(s) 49-50 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(2) 5.5 Page(s) 164-5 CIS Apple OS X 10.12 Benchmark v1.0.0 #. audit_keychain_lock () { print_function "audit_keychain_lock" string="Keychain Lock" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then timeout="21600" if [ "${audit_mode}" != 2 ]; then for check_value in timeout lock-on-sleep; do check_message "Keychain has \"${check_value}\" set" command="security show-keychain-info 2> /dev/null | grep \"${check_value}\" | grep -c \"${timeout}\" | sed 's/ //g'" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "0" ]; then inc_insecure "Keychain \"${check_value}\" does not have \"${timeout}\" set" else inc_secure "Keychain \"${check_value}\" has \"${timeout}\" set" fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_keychain_lock_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"security show-keychain-info 2> /dev/null | grep '${check_value}' | grep -c '${timeout}' | sed 's/ //g'\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} != 0" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" if [ "${check_value}" = "timeout" ]; then echo " command: sh -c \"set-keychain-settings -u -t ${timeout}\"" else echo " command: sh -c \"set-keychain-settings -l -t ${timeout}\"" fi echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" else run_lockdown "sudo /usr/bin/security authorizationdb write system.login.screensaver use-login-window-ui" "Disable ${string}" fi done fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_keychain_sync.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_keychain_sync # # Ensure that the iCloud keychain is used consistently with organizational requirements. # # Refer to ection(s) 2.1.1.1 Page(s) 41-44 CIS macOS 14 Sonoma Benchmark v1.0.0 #. audit_keychain_sync () { print_function "audit_keychain_sync" string="Keychain sync" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then verbose_message "Keychain sync" "check" if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/ | grep \"[a-z]\"" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do command="sudo -u \"${user_name}\" defaults read /Users/${user_name}/Library/Preferences/MobileMeAccounts 2> /dev/null |grep -B 1 KEYCHAIN_SYNC |head -1 |cut -f2 -d= |cut -f1 -d\; |sed 's/ //g'" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" = "${keychain_sync}" ]; then inc_secure "Keychain sync enable for \"${user_name}\" is set to \"${keychain_sync}\"" else inc_insecure "Keychain sync enable for \"${user_name}\" is not set to \"${keychain_sync}\"" fi done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_location_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_location_services # # There are some use cases where it is important that the computer not be able to report # its exact location. While the general use case is to enable Location Services, it should # not be allowed if the physical location of the computer and the user should not be public # knowledge. # # Refer to Section(s) 2.6.1.1-2 Page(s) 153-7 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_location_services () { print_function "audit_location_services" string="Location Services" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${audit_mode}" != 2 ]; then check_osx_defaults_bool "/var/db/locationd/Library/Preferences/ByHost/com.apple.locationd" "LocationServicesEnabled" "0" check_osx_defaults_bool "/Library/Preferences/com.apple.locationmenu.plist" "ShowSystemServices" "1" fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_lockdown.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_lockdown # # When lockdown mode is enabled, specific trusted websites can be excluded from # Lockdown protection if necessary. # # Refer to Section(s) 2.6.7 Page(s) 181-2 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_lockdown () { print_function "audit_lockdown" string="Lockdown Mode" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_bool ".GlobalPreferences" "LDMGlobalEnabled" "1" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_media_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_media_sharing # # Disabling Media Sharing reduces the remote attack surface of the system. # # Refer to Section(s) 2.3.3.10 Page(s) 114-7 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_media_sharing () { print_function "audit_media_sharing" string="Media Sharing" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.amp.mediasharingd" "home-sharing-enabled" "0" "bool" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_remote_apple_events.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_remote_apple_events # # Check Apple remote events # # Refer to Section(s) 5.20 Page(s) 68-9 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.4.2 Page(s) 38 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.3.3.7 Page(s) 106-7 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_remote_apple_events () { print_function "audit_remote_apple_events" string="Remote Apple Events" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1008 ]; then check_osx_systemsetup "getremoteappleevents" "off" else check_launchctl_service "eppc" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_safari_allow_popups.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_safari_allow_popups # # Check Safari Popups # # Refer to Section(s) 6.3.9 Page(s) 406-7 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_safari_allow_popups () { print_function "audit_safari_allow_popups" string="Safari Allow Popups" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.Safari" "safariAllowPopups" "0" "bool" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_safari_auto_fill.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_safari_auto_fill # # Check Safari Auto Fill # # Refer to Section(s) 6.3.8 Page(s) 403-5 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_safari_auto_fill () { print_function "audit_safari_auto_fill" string="Safari Auto Fill" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then user_list=$( find /Users -maxdepth 1 | grep -vE "localized|Shared" | cut -f3 -d/ ) for user_name in ${user_list}; do for parameter in AutoFillFromAddressBook AutoFillPasswords AutoFillCreditCardData AutoFillMiscellaneousForms; do check_osx_defaults_user "com.apple.Safari" "${parameter}" "0" "bool" "${user_name}" done done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_safari_auto_run.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_safari_auto_run # # Check Safari settingd # # Refer to Section(s) 6.3 Page(s) 78 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 6.3-4 Page(s) 164-6 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 6.3.1 Page(s) 369-73 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_safari_auto_run () { print_function "audit_safari_auto_run" string="Safari Auto-run" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then check_osx_defaults_int "com.apple.Safari AutoOpenSafeDownloads" "0" "int" check_osx_defaults_string "$HOME/Library/Preferences/com.apple.safari.plist" "PlugInFirstVisitPolicy" "PlugInPolicyAllowWithSecurityRestrictions" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_safari_history.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_safari_history # # Check Safari history limit # # Refer to Section(s) 6.3.2 Page(s) 374-79 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_safari_history () { print_function "audit_safari_history" string="Safari History" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.Safari" "HistoryAgeInDaysLimit" "31" "int" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_safari_javascript.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_safari_javascript # # Check Safari Javascript # # Refer to Section(s) 6.3.10 Page(s) 408-9 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_safari_javascript () { print_function "audit_safari_javascript" string="Safari Javascript" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.Safari" "WebKitPreferences.javaScriptEnabled" "0" "bool" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_safari_show_statusbar.sh ================================================ #!/bin/sh # shellcheck disable=SC2034 # shellcheck disable=SC1090 # shellcheck disable=SC2154 # audit_safari_show_statusbar # # Check Safari Popups # # Refer to Section(s) 6.3.11 Page(s) 410-11 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_safari_show_statusbar () { print_function "audit_safari_show_statusbar" string="Safari Show Status Bar" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.Safari" "ShowOverlayStatusBar" "1" "bool" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_safari_tracking.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2010 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_safari_tracking # # Check Safari Tracking # # Refer to Section(s) 6.3.4-6 Page(s) 385-402 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_safari_tracking () { print_function "audit_safari_tracking" string="Safari Cross-site Tracking" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="ls /Users | grep -v Shared" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.Safari" "BlockStoragePolicy" "2" "int" "${user_name}" check_osx_defaults_user "com.apple.Safari" "WebKitStorageBlockingPolicy" "1" "int" "${user_name}" check_osx_defaults_user "com.apple.Safari" "WebKitPreferences.storageBlockingPolicy" "1" "int" "${user_name}" check_osx_defaults_user "com.apple.Safari" "WBSPrivacyProxyAvailabilityTraffic" "33422572" "int" "${user_name}" check_osx_defaults_user "com.apple.Safari" "WebKitPreferences.privateClickMeasurementEnabled" "1" "bool" "${user_name}" check_osx_defaults_user "com.apple.Safari" "ShowFullURLInSmartSearchField" "1" "bool" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_safari_warn.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_safari_warn # # Attackers use crafted web pages to social engineer users to load unwanted content. # Warning users prior to loading the content enables better security. # # Refer to Section(s) 6.3.2 Page(s) 380-4 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_safari_warn () { print_function "audit_safari_warn" string="Safari Fraudulent Website Warning" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.Safari" "WarnAboutFraudulentWebsites" "1" "bool" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_safe_downloads.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_safe_downloads # # Check safe downloads # # Refer to Section(s) 2.6.3 Page(s) 29-30 CIS Apple OS X 10.8 Benchmark v1.0.0 #. audit_safe_downloads () { print_function "audit_safe_downloads" string="Safe Downloads list" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then update_file="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.plist" if [ ! -f "${update_file}" ]; then actual_value="not-found" else actual_value=$( find "${update_file}" -mtime -30 ) fi if [ "${actual_value}" != "${update_file}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Safe Downloads list has not be updated recently" notice_message "Open System Preferences" notice_message "Select Security & Privacy" notice_message "Select the General tab" notice_message "Select Advanced" notice_message "Check Automatically update safe downloads list" notice_message "sudo /usr/libexec/XProtectUpdater" fi if [ "${audit_mode}" = 0 ]; then verbose_message "Updating: Safe Downloads list" sudo /usr/libexec/XProtectUpdater fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Safe Downloads list has been updated recently" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_screen_corner.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_screen_corner # # Hot Corners can be configured to disable the screen saver by moving the mouse cursor # to a corner of the screen. # # Refer to Section(s) 2.7.1 Page(s) 188-92 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_screen_corner () { print_function "audit_screen_corner" string="Screen Saver Corners" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do for corner in wvous-tl-corner wvous-bl-corner wvous-tr-corner wvous-tr-corner; do check_osx_defaults_user "com.apple.NetworkBrowser" "${corner}" "6" "int" "${user_name}" done done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_screen_lock.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_screen_lock # # Setting an inactivity interval for the screen saver prevents unauthorized persons from # viewing a system left unattended for an extensive period of time. # # Refer to Section(s) 2.3.1-2 Page(s) 13-14 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.3.1-2,4,5.9,11 Page(s) 32-4,7,137,140-1 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 5.5 Page(s) 51-52 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.10.1 Page(s) 218-21 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_screen_lock () { print_function "audit_screen_lock" string="Screen Lock" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.screensaver" "idleTime" "600" "int" "currentHost" "${user_name}" done fi fi check_message "Screen Lock" check_osx_defaults_host "com.apple.screensaver" "askForPassword" "1" "int" check_osx_defaults_host "com.apple.screensaver" "idleTime" "900" "int" check_append_file "/etc/pam.d/screensaver" "account required pam_group.so no_warn group=admin,wheel fail_safe" "hash" if [ "${audit_mode}" != 2 ]; then if [ -f "$HOME/Library/Preferences/com.apple.dock" ]; then command="defaults read ~/Library/Preferences/com.apple.dock |grep corner |grep -c 1 |sed \"s/ //g\"" command_message "${command}" screen_test=$( eval "${command}" ) if [ "${screen_test}" = "1" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Screensaver disable hot corner is enabled" fi if [ "${audit_mode}" = 1 ] || [ "${audit_mode}" = 0 ]; then fix_message "Open System Preferences" fix_message "Mission Control" fix_message "Hot Corners" fix_message "Remove any corners which are set to Disable Screen Saver" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "No screensaver disable hot corners enabled" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "No screensaver disable hot corners enabled" fi fi else notice_message "Open System Preferences" notice_message "Mission Control" notice_message "Hot Corners" notice_message "Remove any corners which are set to Disable Screen Saver" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_screen_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_screen_sharing # # Check sreen sharing settings # # Refer to Section(s) 2.4.3 Page(s) 40 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.3.3.2 Page(s) 92-4 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 # # Refer to http://support.apple.com/kb/ph11151 #. audit_screen_sharing () { print_function "audit_screen_sharing" string="Screen Sharing" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then check_launchctl_service "com.apple.screensharing" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_siri.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_siri # # Where "normal" user activity is already limited, Siri use should be controlled as well. # # Refer to Section(s) 2.5.1 Page(s) 141-8 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_siri () { print_function "audit_siri" string="Siri Settings" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.Siri.plist" "StatusMenuVisible" "1" "bool" "${user_name}" check_osx_defaults_user "com.apple.Siri.plist" "LockscreenEnabled" "0" "bool" "${user_name}" check_osx_defaults_user "com.apple.Siri.plist" "VoiceTriggerUserEnabled" "0" "bool" "${user_name}" check_osx_defaults_user "com.apple.Siri.plist" "TypeToSiriEnabled" "0" "bool" "${user_name}" check_osx_defaults_user "com.apple.assistant.support.plist" "Assistant Enabled" "0" "bool" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_sleep.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sleep # # MacBooks should be set so that the standbydelay is 15 minutes (900 seconds) or less. # This setting should allow laptop users in most cases to stay within physically secured # areas while going to a conference room, auditorium, or other internal location without # having to unlock the encryption. When the user goes home at night, the laptop will auto- # hibernate after 15 minutes and require the FileVault password to unlock prior to logging # back into the system when it resumes. # MacBooks should also be set to a hibernate mode that removes power from the RAM. # This will stop the possibility of cold boot attacks on the system. # Macs running Apple silicon chips, rather than Intel chips, do not require the same # configuration as Intel-based Macs. # # Full Disk Encryption (FDE) is a Data-at-Rest (DAR) solution. It ensures that when the # data on the drive is not in use it is full encrypted, but it can be decrypted (unlocked) as # needed. When a Mac sleeps, the encryption keys remain in memory so that the drive is # encrypted but unlocked. There are attacks available to interact with the OS and data on # the unlocked drive. FileVault volumes should be locked when not in use to resist attack. # The purpose of DAR is to ensure data is encrypted while at rest. If the volume is always # unlocked it is not sufficient. # # Refer to Section(s) 2.5.2 Page(s) 52-3 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.9.1.1-3,2.9.2 Page(s) 200-11 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_sleep () { print_function "audit_sleep" string="Sleep" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${os_machine}" = "arm64" ]; then check_pmset "sleep" "10" check_pmset "displaysleep" "15" check_pmset "hibernatemode" "25" else check_pmset "standbydelaylow" "900" check_pmset "standbydelayhigh" "900" check_pmset "highstandbythreshold" "90" check_pmset "destroyfvkeyonstandby" "1" check_pmset "hibernatemode" "25" check_pmset "powernap" "0" fi check_pmset "destroyfvkeyonstandby" "1" else check_pmset "sleep" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_software_update.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_software_update # # Check software update settings # # Refer to http://pubs.vmware.com/vsphere-55/topic/com.vmware.vsphere.update_manager.doc/GUID-EF6BEE4C-4583-4A8C-81B9-5B074CA2E272.html # # Refer to Page(s) 8 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 1.2-5 Page(s) 13-20 CIS Apple OS X 10.12 Benchmark v1.0.0o # Refer to Section(s) 1.2-7 Page(s) 16-34 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_software_update () { print_function "audit_software_update" string="Software Update" check_message "${string}" if [ "${os_name}" = "VMkernel" ]; then vmware_depot="http://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml" current_update=$( esxcli software profile get 2>&1 | head -1 ) log_file="softwareupdate.log" backup_file="${work_dir}/${log_file}" command="esxcli software sources profile list -d \"${vmware_depot}\" | grep \"${os_version}\" | head -1 | awk '{print \$1}'" command_message "${command}" available_update=$( eval "${command}" ) if [ "${audit_mode}" != 2 ]; then if [ "${current_update}" != "${available_update}" ]; then if [ "${audit_mode}" = 0 ]; then notice_message "Updating software" esxcli software profile install -d "${vmware_depot}" -p "${available_update}" --ok-to-remove fi if [ "${audit_mode}" = 1 ]; then inc_insecure "Software is not up to date (Current: ${current_update} Available: ${available_update})" fix_message "esxcli software profile install -d ${vmware_depot} -p ${available_update} --ok-to-remove" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Software is up to date" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then previous_update=$( cat "${restore_file}" ) if [ "${current_update}" != "${previous_update}" ]; then restore_message "Software to \"${previous_value}\"" esxcli software profile install -d "${vmware_depot}" -p "${previous_update}" --ok-to-remove --alow-downgrades fi fi fi fi if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1012 ]; then check_osx_defaults_int "/Library/Preferences/com.apple.SoftwareUpdate" "AutomaticCheckEnabled" "1" check_osx_defaults_bool "/Library/Preferences/com.apple.commerce" "AutoUpdate" "1" check_osx_defaults_bool "/Library/Preferences/com.apple.SoftwareUpdate" "ConfigDataInstall" "1" check_osx_defaults_bool "/Library/Preferences/com.apple.SoftwareUpdate" "CriticalUpdateInstall" "1" check_osx_defaults_bool "/Library/Preferences/com.apple.commerce" "AutoUpdateRestartRequired" "1" if [ "${long_os_version}" -ge 1013 ]; then check_osx_defaults_bool "/Library/Preferences/com.apple.SoftwareUpdate" "AutomaticDownload" "1" check_osx_defaults_bool "/Library/Preferences/com.apple.SoftwareUpdate" "AutomaticallyInstallMacOSUpdates" "1" fi else check_message "Software Autoupdate" if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi command="sudo softwareupdate --schedule |awk '{print \$4}'" command_message "${command}" actual_status=$( eval "${command}" ) log_file="softwareupdate.log" correct_status="on" if [ "${audit_mode}" != 2 ]; then verbose_message "If Software Update is enabled" if [ "${actual_status}" != "${correct_status}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Software Update is not \"${correct_status}\"" command_line="sudo softwareupdate --schedule ${correct_status}" fix_message "${command_line}" else if [ "${audit_mode}" = 0 ]; then log_file="${work_dir}/${log_file}" echo "${actual_status}" > "${log_file}" set_message "Software Update schedule to \"${correct_status}\"" sudo softwareupdate --schedule ${correct_status} fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Software Update is ${correct_status}" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then previous_status=$( cat "${restore_file}" ) if [ "${previous_status}" != "${actual_status}" ]; then restore_message "Software Update to \"${previous_status}\"" sudo softwareupdate --schedule "${previous_status}" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_sys_suspend.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sys_suspend # # Refer to Section(s) 10.4 Page(s) 140 CIS Solaris 10 Benchmark v1.1.0 #. audit_sys_suspend () { print_function "audit_sys_suspend" string="System Suspend" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/default/sys-suspend" "PERMS" "eq" "-" "hash" else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_system_preferences.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_preferences # # Chec whether a password is required to access system-wide preferences # # Refer to Section(s) 5.8 Page(s) 138-9 CIS Apple OS X 10.12 Benchmark v1.0.0 #. audit_system_preferences () { print_function "audit_system_preferences" string="System Preferences" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ ! "${audit_mode}" != 2 ]; then check=$( security authorizationdb read system.preferences 2> /dev/null | grep -A1 shared | grep true ) if [ "${check}" ]; then inc_insecure "An Administrator password is not required to access system-wide preferences" else inc_secure "An Administrator password is required to access system-wide preferences" fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_time_machine.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_time_machine # # Backups should automatically run whenever the backup drive is available. # # Refer to Section(s) 2.3.4.1 Page(s) 125-8 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_time_machine () { print_function "audit_time_machine" string="Time Machine" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${os_version}" -ge 14 ]; then check_osx_defaults_bool "/Library/Preferences/com.apple.TimeMachine.plist" "AutoBackup" "1" fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_touch_id.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_touch_id # # Touch ID allows for an account-enrolled fingerprint to access a key that uses a # previously provided password. # # Refer to Section(s) 2.11.2 Page(s) 237-40 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_touch_id () { print_function "audit_touch_id" string="Touch ID" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then get_command="sudo bioutil -r -s | grep timeout | head -1 | cut -f2 -d: | grep -c ${touchid_timeout} | sed 's/ //g'" set_command="/usr/bin/sudo usr/bin/bioutil -w -s -o ${touchid_timeout}" check_value=$( eval "${get_command}" ) if [ "${check_value}" = "${touchid_timeout}" ]; then inc_secure "Touch ID Timeout for system is set to \"${touchid_timeout}\"" else inc_insecure "Touch ID Timeout for system is not set to \"${touchid_timeout}\"" fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_touch_id_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} != 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" else lock_command="${set_command}" lock_message="${string}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi for item in unlock ApplePay ; do string="Touch ID ${item}" check_message "${string}" command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do command="sudo -u \"${user_name}\" bioutil -r -s | grep \"${item}\" | head -1 | cut -f2 -d: | sed \"s/ //g\" > /dev/null 2>&1" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" = "${touchid_timeout}" ]; then inc_secure "Touch ID Timeout for user \"${user_name}\" is set to \"${touchid_timeout}\"" else inc_insecure "Touch ID Timeout for for user \"${user_name}\" is not set to \"${touchid_timeout}\"" fi if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string} for ${user_name}" echo " command: sh -c \"sudo -u ${user_name} bioutil -r -s | grep ${item} | head -1 | cut -f2 -d: | sed 's/ //g'\"" echo " register: audit_touch_id_check" echo " failed_when: audit_touch_id_check != 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" if [ "${item}" = "unlock" ]; then echo " command: sh -c \"/usr/bin/sudo usr/bin/bioutil -w -u 1\"" else echo " command: sh -c \"/usr/bin/sudo usr/bin/bioutil -w -a 1\"" fi echo " when: audit_touch_id_check.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" else if [ "${item}" = "unlock" ]; then lock_command="/usr/bin/sudo usr/bin/bioutil -w -u 1" else lock_command="/usr/bin/sudo usr/bin/bioutil -w -s 1" fi fi lock_message="${string}" run_lockdown "${lock_command}" "${lock_message}" "sudo" done done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_universal_control.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_universal_control # # Universal Control is an Apple feature that allows Mac users to control multiple other # Macs and iPads with the same keyboard, mouse, and trackpad using the same Apple # ID. The technology relies on already available iCloud services, particularly Handoff. # # Refer to Section(s) 2.8.1 Page(s) 194-7 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_universal_control () { print_function "audit_universal_control" string="Universal Control" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do for parameter in Disable DisableMagicEdges; do check_osx_defaults_user "com.apple.universalcontrol" "${parameter}" "1" "bool" "${user_name}" done done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_usage_data.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_usage_data # # Apple provides a mechanism to send diagnostic and analytics data back to Apple to # help them improve the platform. Information sent to Apple may contain internal # organizational information that should be controlled and not available for processing by # Apple. Turn off all Analytics and Improvements sharing. # # Refer to Section(s) 2.6.3 Page(s) 164-9 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_usage_data () { print_function "audit_usage_data" string="Usage Data" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${long_os_version}" -ge 1014 ]; then check_osx_defaults_bool "Library/Application Support/CrashReporter/DiagnosticMessagesHistory.plist" "AutoSubmit" "0" check_osx_defaults_bool "Library/Application Support/CrashReporter/DiagnosticMessagesHistory.plist" "ThirdPartyDataSubmit" "0" check_file_perms "/Library/Application Support/CrashReporter/DiagnosticMessagesHistory.plist" "644" "root" "admin" check_message "Siri Data Sharing" if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${audit_mode}" != 2 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.assistant.support" "Siri Data Sharing Opt-In Status" "2" "int" "${user_name}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_wake_on_lan.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_wake_on_lan # # Refer to Section(s) 2.5.1 Page(s) 26-7 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.5.1 Page(s) 50-1 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.9.3 Page(s) 212-6 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_wake_on_lan() { print_function "audit_wake_on_lan" string="Wake on Lan" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_pmset "womp" "off" else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_web_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_web_sharing # # Turn off web sharing # # Refer to Section(s) 1.4.14.7 Page(s) 55-6 CIS Apple OS X 10.7 Benchmark v1.0.0 # Refer to Section(s) 4.4 Page(s) 101-2 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 4.2 Page(s) 292-3 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_web_sharing () { print_function "audit_web_sharing" string="Web sharing" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_file_value "is" "/etc/apache2/httpd.conf" "ServerTokens" "space" "Prod" "hash" check_file_value "is" "/etc/apache2/httpd.conf" "ServerSignature" "space" "Off" "hash" check_file_value "is" "/etc/apache2/httpd.conf" "UserDir" "space" "Disabled" "hash" check_file_value "is" "/etc/apache2/httpd.conf" "TraceEnable" "space" "Off" "hash" check_launchctl_service "org.apache.httpd" "off" else na_message "${string}" fi } ================================================ FILE: modules/darwin/audit_wireless.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_wireless # # Wireless checks # # Refer to Section(s) 4.2 Page(s) 98-9 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 3.1.2 Page(s) 177-9 CIS Ubuntu 22.04 Benchmark v1.0.0 # Refer to Section(s) 3.1.2 Page(s) 357-60 CIS Ubuntu 24.04 Benchmark v1.0.0 # Refer to Section(s) 2.4.1 Page(s) 133-6 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_wireless () { print_function "audit_wireless" string="Wifi information menu" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi if [ "${os_name}" = "Darwin" ] && [ "${os_version}" -ge 14 ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do check_osx_defaults_user "com.apple.controlcenter.plist" "WiFi" "2" "int" "currentHost" "${user_name}" done else # answer="/System/Library/CoreServices/MenuExtras/AirPort.menu" command="defaults read com.apple.systemuiserver menuExtras 2> /dev/null | grep \"AirPort.menu\" | sed \"s/[ ,\\\",\\\,]//g\" | grep -c \"AirPort\" |sed \"s/ //g\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" = "0" ]; then inc_secure "Wireless status menu is not enabled" else inc_insecure "Wireless status menu is enabled" fi fi else if [ "${os_name}" = "Linux" ]; then command="command -v nmcli 2> /dev/null | sed \"s/ //g\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" = "1" ]; then command="nmcli radio all | grep -c enabled" command_message "${command}" check=$( eval "${command}" ) else command="find /sys/class/net/*/ -type d -name wireless | wc -l | sed \"s/ //g\"" command_message "${command}" check=$( eval "${command}" ) fi if [ "${check}" = "0" ]; then inc_secure "Wireless is enabled" else inc_insecure "Wireless not enabled" fi else na_message "${string}" fi fi } ================================================ FILE: modules/dhcp/audit_dhcp_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dhcp_server # # Check DHCP server # # Refer to Section(s) 3.5 Page(s) 61-2 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.3 Page(s) 74 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.5 Page(s) 64-5 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.5 Page(s) 105 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.4 Page(s) 54-5 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.2.5 Page(s) 97 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.5 Page(s) 105 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.3 Page(s) 234-6 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_dhcp_server () { print_function "audit_dhcp_server" string="DHCP Server" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/dhcp-server:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "isc-dhcp-server" "off" check_linux_service "isc-dhcp-server6" "off" check_linux_service "dhcpd" "off" check_linux_package "uninstall" "dhcpd" check_linux_package "uninstall" "isc-dhcp-server" fi else na_message "${string}" fi } ================================================ FILE: modules/dhcp/audit_dhcpcd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dhcpcd # # Check DHCP client # # Refer to Section(s) 1.3.8 Page(s) 43-4 CIS AIX Benchmark v1.1.0 #. audit_dhcpcd () { print_function "audit_dhcpcd" string="DHCP Client Daemon" check_message "${string}" if [ "${dhcpcd_disable}" = "yes" ]; then if [ "${os_name}" = "AIX" ]; then check_rctcp "dhcpcd" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/dhcp/audit_dhcprd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dhcprd # # Check DHCP relay # # Refer to Section(s) 1.3.9 Page(s) 44-5 CIS AIX Benchmark v1.1.0 #. audit_dhcprd () { print_function "audit_dhcprd" string="DHCP Relay Daemon" check_message "${string}" if [ "${dhcprd_disable}" = "yes" ]; then if [ "${os_name}" = "AIX" ]; then check_rctcp "dhcprd" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/dhcp/audit_dhcpsd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dhcpscd # # Check DHCP server # # Refer to Section(s) 1.3.10 Page(s) 45-6 CIS AIX Benchmark v1.1.0 #. audit_dhcpsd () { print_function "audit_dhcpsd" string="DHCP Server Daemon" check_message "${string}" if [ "${dhcpsd_disable}" = "yes" ]; then if [ "${os_name}" = "AIX" ]; then check_rctcp "dhcpsd" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/dns/audit_dns_client.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dns_client # # Turn off Name Server Caching Daemon #. audit_dns_client () { print_function "audit_dns_client" string="Name Server Caching Daemon" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_linux_service "nscd" "off" else na_message "${string}" fi } ================================================ FILE: modules/dns/audit_dns_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dns_server # # Refer to Section(s) 3.9 Page(s) 65-6 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.9 Page(s) 77-8 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.9 Page(s) 68 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.8 Page(s) 108 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.8 Page(s) 58 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 3.6 Page(s) 11 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.3.14 Page(s) 50-1 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 2.2.8 Page(s) 100 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.8-9 Page(s) 108-9 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.4-5 Page(s) 237-41 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_dns_server () { print_function "audit_dns_server" string="DNS Server" check_message "${string}" if [ "${named_disable}" = "yes" ]; then if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then verbose_message "DNS Server" "check" if [ "${os_name}" = "AIX" ]; then check_rctcp "named" "off" fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/dns/server:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then for service_name in dnsmasq named bind9; do check_linux_service "${service_name}" "off" check_linux_package "uninstall" "${service_name}" done if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "Amazon" ]; then check_linux_package "uninstall" "bind" fi fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/rc.conf" "named_enable" "eq" "NO" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/docker/audit_docker_daemon.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_docker_daemon # # Check that Docker daemon activities are audited # # Refer to Section(s) 1.5-13 Page(s) 18-35 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 2.4-13 Page(s) 41-58 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 2.14 Page(s) 60-1 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 2.18 Page(s) 67-8 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 2.20-3 Page(s) 70-5 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 3.1-20 Page(s) 77-104 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.10-1 Page(s) 142-5 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.14 Page(s) 150-1 CIS Docker Benchmark 1.13.0 # # Refer to https://containerd.tools/ # Refer to https://windsock.io/the-docker-proxy/ # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html # Refer to https://man7.org/linux/man-pages/man7/user_namespaces.7.html # Refer to https://github.com/twistlock/authz # Refer to https://github.com/docker/docker-registry/issues/612 # Refer to https://github.com/docker/docker/issues/8093 # Refer to https://github.com/docker/docker/issues/9015 # Refer to https://github.com/docker/docker/issues/14856 # Refer to https://github.com/docker/docker/issues/21050 # Refer to https://github.com/docker/docker/issues/22741 # Refer to https://github.com/docker/docker/issues/26713 # Refer to https://github.com/docker/docker/pull/20662 # Refer to https://github.com/docker/docker/pull/23213 # Refer to https://github.com/docker/docker/pull/26276 # Refer to https://github.com/docker/docker/pull/27223 # Refer to https://github.com/opencontainers/runc # Refer to https://github.com/YungSang/fedora-atomic-packer/blob/master/oem/docker.socket # Refer to https://github.com/mstanleyjones/docker.github.io/blob/af7dfdba8504f9b102fb31a78cd08a06c33a8975/engine/swarm/swarm_manager_locking.md # Refer to https://docs.docker.com/registry/insecure/ # Refer to https://docs.docker.com/articles/https/ # Refer to https://docs.docker.com/engine/reference/commandline/daemon/#daemon-configuration-file # Refer to https://docs.docker.com/reference/commandline/cli/#daemon-storage-driver-option # Refer to https://docs.docker.com/engine/userguide/storagedriver/ # Refer to https://docs.docker.com/engine/reference/commandline/daemon/ # Refer to https://docs.docker.com/engine/reference/commandline/daemon/#default-ulimits # Refer to https://docs.docker.com/engine/reference/commandline/daemon/#storage-driver-options # Refer to https://docs.docker.com/engine/reference/commandline/daemon/#access- authorization # Refer to https://docs.docker.com/engine/extend/authorization/ # Refer to https://docs.docker.com/registry/spec/api/ # Refer to https://docs.docker.com/engine/userguide/networking/default_network/binding/ # Refer to https://docs.docker.com/engine/admin/systemd/ # Refer to https://docs.docker.com/articles/basics/#bind-docker-to-another-hostport-or-a-unix-socket # Refer to https://docs.docker.com/articles/certificates/ # Refer to https://docs.docker.com/reference/commandline/cli/#insecure-registries # Refer to https://docs.docker.com/reference/commandline/cli/#daemon-socket-option # Refer to https://docs.docker.com/articles/basics/#bind-docker-to-another-hostport-or-a-unix-socket # Refer to https://docs.docker.com/engine/reference/commandline/daemon/#daemon-configuration-file # Refer to https://docs.docker.com/engine/admin/configuring/ # Refer to https://docs.docker.com/articles/runmetrics/ # Refer to https://docs.docker.com/reference/commandline/cli/#run # Refer to https://docs.docker.com/reference/commandline/cli/#restart-policies # Refer to https://www.slideshare.net/Docker/docker-registry-v2 # Refer to https://goldmann.pl/blog/2014/09/11/resource-management-in-docker/ # Refer to https://goldmann.pl/blog/2014/09/11/resource-management-in-docker/ # Refer to https://muehe.org/posts/switching-docker-from-aufs-to-devicemapper/ # Refer to https://daviddaeschler.com/2014/12/14/centos-7rhel-7-and-docker-containers-on-boot/ # Refer to https://blog.docker.com/2015/07/new-tool-v1-registry-docker-trusted-registry-v2-open-source/ # Refer to https://events.linuxfoundation.org/sites/events/files/slides/User%20Namespaces%20-%20ContainerCon%202015%20-%2016-9-final_0.pdf # Refer to https://daviddaeschler.com/2014/12/14/centos-7rhel-7-and-docker-containers-on-boot/ # Refer to https://jpetazzo.github.io/assets/2015-03-05-deep-dive-into-docker-storage-drivers.html#1 # Refer to https://the.binbashtheory.com/creating-private-docker-registry-2-0-with-token-authentication-service/ #. audit_docker_daemon () { print_function "audit_docker_daemon" string="Docker Daemon" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then docker_bin=$( command -v docker ) if [ "${docker_bin}" ]; then check_file="/etc/audit/audit.rules" for docker_file in /usr/bin/docker /var/lib/docker /etc/docker /etc/default/docker /etc/docker/daemon.json /usr/bin/docker-containerd /usr/bin/docker-runc; do check_auditctl "${docker_file}" "docker_file" check_append_file "${check_file}" "-w ${docker_file} -k docker" "hash" done systemctl_check=$( command -v systemctl ) if [ "${systemctl_check}" ]; then for docker_service in docker.service docker.socket; do check_auditctl "${docker_service}" "docker_service" docker_file=$( systemctl show -p FragmentPath ${docker_service} 2> /dev/null ) check_append_file "${check_file}" "-w ${docker_file} -k docker" "hash" check_file_perms "${check_file}" "0640" "root" "root" done fi for check_file in /etc/docker /etc/docker/certs.d; do check_file_perms ${check_file} 0750 root root done if [ -e "/etc/docker/certs.d" ]; then file_list=$( find /etc/docker/certs.d/ -type f ) for check_file in ${file_list}; do check_file_perms "${check_file}" "440" "root" "root" done fi check_file_perms /var/run/docker.sock 660 root docker for check_file in /etc/default/docker /etc/docker/daemon.json; do check_file_perms "${check_file}" "640" "root" "root" done tlscert_file="" tlscacert_file="" tlskey_file="" for check_file in ${tlscert_file} ${tlscacert_file} ${tlskey_file}; do check_file_perms "${check_file}" "400" "root" "root" done check_dockerd "unused" "daemon" "insecure-registry" "" check_dockerd "unused" "daemon" "storage-driver" "aufs" check_dockerd "unused" "daemon" "net host" "" check_dockerd "unused" "info" "Storage Driver" "aufs" check_dockerd "used" "daemon" "tlsverify" "" check_dockerd "used" "daemon" "tlscacert" "" check_dockerd "used" "daemon" "tlscert" "" check_dockerd "used" "daemon" "tlskey" "" check_dockerd "used" "daemon" "default-ulimit" "" check_dockerd "used" "daemon" "cgroup-parent" "" check_dockerd "used" "daemon" "userns-remap" "" check_file_exists "/etc/subuid" "yes" check_file_exists "/etc/subgid" "yes" check_dockerd "unused" "daemon" "storage-opt" check_dockerd "used" "daemon" "authorization-plugin" "" check_dockerd "used" "daemon" "disable-legacy-registry" "" check_dockerd "used" "daemon" "live-restore" "" check_dockerd "used" "daemon" "userland-proxy" "false" check_dockerd "used" "daemon" "seccomp-profile" "" check_dockerd "unused" "daemon" "experimental" "" if [ "${audit_mode}" != 2 ]; then check=$( docker swarm unlock-key 2> /dev/null ) if [ "${check}" = "no unlock key is set" ]; then inc_insecure "Docker swarm unlock is not set" else inc_secure "Docker swarm unlock key is not set or swarm is not running" fi check_dockerd "notequal" "config" "Memory" "0" check_dockerd "notequal" "config" "CpuShares" "0" check_dockerd "notequal" "config" "CpuShares" "1024" check_dockerd "notequal" "config" "RestartPolicy.Name" "always" check_dockerd "equal" "config" "RestartPolicy.Name" "on-failure" check_dockerd "equal" "config" "MaximumRetryCount" "5" fi fi else na_message "${string}" fi } ================================================ FILE: modules/docker/audit_docker_logging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_docker_logging # # Check Docker logging # # Refer to Section(s) 2.2 Page(s) 38 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 2.12 Page(s) 56-7 CIS Docker Benchmark 1.13.0 # # Refer to https://docs.docker.com/engine/reference/commandline/daemon/ # Refer to https://docs.docker.com/engine/admin/logging/overview/ #. audit_docker_logging () { print_function "audit_docker_logging" string="Docker Logging" check_message "${string}" if [ "${os_name}" = "Linux" ]; then docker_bin=$( command -v docker ) if [ "${docker_bin}" ]; then check_dockerd "unused" "daemon" "log-level" "info" check_dockerd "used" "daemon" "log-driver" "" check_dockerd "used" "daemon" "log-opt" "" fi else na_message "${string}" fi } ================================================ FILE: modules/docker/audit_docker_monitoring.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_docker_monitoring # # Check Docker monitoring # # Refer to Section(s) 4.6 Page(s) 115 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.26 Page(s) 172 CIS Docker Benchmark 1.13.0 # # Refer to https://github.com/docker/docker/pull/22719 # Refer to https://github.com/docker/docker/pull/22719 #. audit_docker_monitoring () { print_function "audit_docker_monitoring" string="Docker Healthcheck" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then docker_bin=$( command -v docker ) if [ "${docker_bin}" ]; then string="Docker Healthcheck" check_message "${string}" check_dockerd "equal" "config" "Health" "" docker_ids=$( docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}' 2> /dev/null ) for docker_id in ${docker_ids}; do check=$( docker inspect --format='{{ .Config.Healthcheck }}' "${docker_id}" ) if [ ! "${check}" = "" ]; then inc_secure "Docker instance \"${docker_id}\" has a Healthcheck instruction" else inc_insecure "Docker instance \"${docker_id}\" has no Healthcheck instruction" fi done fi fi else na_message "${string}" fi } ================================================ FILE: modules/docker/audit_docker_network.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_docker_network # # Check that Docker does not allow communication between containers # # Refer to Section(s) 2.1 Page(s) 36-7 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 2.3 Page(s) 39-40 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 2.19 Page(s) 69 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.13 Page(s) 148-9 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.29 Page(s) 177 CIS Docker Benchmark 1.13.0 # # Refer to https://arxiv.org/pdf/1501.02967 # Refer to https://github.com/nyantec/narwhal # Refer to https://github.com/docker/docker/issues/24253 # Refer to https://docs.docker.com/articles/networking # Refer to https://docs.docker.com/engine/userguide/networking/overlay-security-model/ # Refer to https://docs.docker.com/articles/networking/#binding-container-ports-to-the-host # Refer to https://docs.docker.com/engine/userguide/networking/dockernetworks/ #. audit_docker_network () { print_function "audit_docker_network" string="Docker Network" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then docker_bin=$( command -v docker ) if [ "${docker_bin}" ]; then backup_file="network_bridge" new_state="false" old_state="true" if [ "${audit_mode}" != 2 ]; then check_dockerd notequal config NetworkMode "NetworkMode=host" check_dockerd notinclude config Ports "0.0.0.0" docker_check=$( docker network ls --quiet | xargs docker network inspect --format '{{ .Name }}: {{ .Options }}' | grep 'docker0' ) if [ "${docker_check}" ]; then inc_insecure "Docker is using default bridge docker0" else inc_secure "Docker is not using default bridge docker0" fi docker_check=$( docker network ls --quiet | xargs docker network inspect --format '{{ .Name }}: {{ .Options }}' | grep 'com.docker.network.bridge.enable_icc' | grep "${new_state}" ) if [ ! "${docker_check}" ]; then inc_insecure "Traffic is allowed between containers" if [ "${audit_mode}" = 0 ]; then log_file="${work_dir}/${backup_file}" echo "${old_state}" > "${log_file}" set_message "Docker network bridge enabled to \"${new_state}\"" eval "/usr/bin/dockerd --icc=${new_state}" fi else inc_secure "Traffic is not allowed between containers" fi else restore_file="${restore_dir}/${backup_file}" old_state=$( cat "${restore_file}" ) restore_message "Docker network bridge enabled to \"${old_state}\"" eval "/usr/bin/dockerd --icc=${old_state}" fi check_dockerd "unused" "daemon" "iptables" "true" check_dockerd "used" "daemon" "opt" "encrypted" fi else na_message "${string}" fi } ================================================ FILE: modules/docker/audit_docker_security.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_docker_security # # Docker security # # Refer to Section(s) 2.8 Page(s) 49-50 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.1-4 Page(s) 126-32 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.9 Page(s) 141 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.12 Page(s) 146-7 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.15-7 Page(s) 152-9 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.19-25 Page(s) 160-71 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.28 Page(s) 175-6 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.30 Page(s) 178 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 5.31 Page(s) 179 CIS Docker Benchmark 1.13.0 # # Refer to https://lwn.net/Articles/475678/ # Refer to https://lwn.net/Articles/475362/ # Refer to https://docs.docker.com/articles/networking/#how-docker-networks-a-container # Refer to https://docs.docker.com/articles/security/#linux-kernel-capabilities # Refer to https://docs.docker.com/articles/security/#other-kernel-security-features # Refer to https://docs.docker.com/engine/security/apparmor/ # Refer to https://docs.docker.com/engine/reference/commandline/run/ # Refer to https://docs.docker.com/engine/reference/commandline/run/#/run # Refer to https://docs.docker.com/engine/security/seccomp/ # Refer to https://docs.docker.com/engine/reference/commandline/exec/ # Refer to https://docs.docker.com/engine/reference/run/#specifying-custom-cgroups # Refer to https://docs.docker.com/engine/reference/run/ # Refer to https://docs.docker.com/reference/run/#security-configuration # Refer to https://docs.docker.com/reference/run/#security-configuration # Refer to https://docs.docker.com/reference/commandline/cli # Refer to https://docs.docker.com/reference/commandline/cli/#run # Refer to https://docs.docker.com/reference/run/#pid-settings # Refer to https://docs.docker.com/reference/run/#pid-settings # Refer to https://docs.docker.com/reference/commandline/cli/#run # Refer to https://docs.docker.com/reference/commandline/cli/#setting-ulimits-in-a-container # Refer to https://docs.docker.com/engine/reference/commandline/daemon/ # Refer to https://docs.fedoraproject.org/en-US/Fedora/13/html/Security-Enhanced_Linux/ # Refer to https://github.com/docker/docker/blob/master/docs/security/apparmor.md # Refer to https://github.com/docker/docker/blob/master/daemon/execdriver/native/template/default_template.go # Refer to https://github.com/docker/docker/blob/master/profiles/seccomp/default.json # Refer to https://github.com/docker/docker/issues/6401 # Refer to https://github.com/docker/docker/issues/21050 # Refer to https://github.com/docker/docker/issues/21109 # Refer to https://github.com/docker/docker/issues/22870 # Refer to https://github.com/docker/docker/pull/12648 # Refer to https://github.com/docker/docker/pull/17034 # Refer to https://github.com/docker/docker/pull/18697 # Refer to https://github.com/docker/docker/pull/20727 # Refer to https://github.com/projectatomic/atomic-site/issues/269 # Refer to https://man7.org/linux/man-pages/man7/capabilities.7.html # Refer to https://man7.org/linux/man-pages/man7/pid_namespaces.7.html # Refer to https://man7.org/linux/man-pages/man7/user_namespaces.7.html # Refer to https://man7.org/linux/man-pages/man7/namespaces.7.html # Refer to https://www.oreilly.com/webops-perf/free/files/docker-security.pdf # Refer to https://www.oreilly.com/webops-perf/free/files/docker-security.pdf # Refer to https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt # Refer to https://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt # Refer to https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt # Refer to https://blog.scalock.com/new-docker-security-features-and-what-they-mean-seccomp-profiles # Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Resource_Management_Guide/ch01.html # Refer to https://events.linuxfoundation.org/sites/events/files/slides/User%20Namespaces%20-%20ContainerCon%202015%20-%2016-9-final_0.pdf # Refer to https://events.linuxfoundation.org/sites/events/files/slides/User%20Namespaces%20-%20ContainerCon%202015%20-%2016-9-final_0.pdf # Refer to https://raesene.github.io/blog/2016/03/06/The-Dangers-Of-Docker.sock/ # Refer to https://forums.docker.com/t/docker-in-docker-vs-mounting-var-run-docker-sock/9450/2 #. audit_docker_security () { print_function "audit_docker_security" string="Docker Security" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then docker_bin=$( command -v docker ) if [ "${docker_bin}" ]; then check_dockerd "notequal" "config" "SecurityOpt" "" check_dockerd "include" "config" "SecurityOpt" "userns" check_dockerd "include" "config" "SecurityOpt" "no-new-privileges" check_dockerd "equal" "config" "Privileged" "false" check_dockerd "notequal" "config" "AppArmorProfile" "" check_dockerd "equal" "config" "ReadonlyRootfs" "true" check_dockerd "notequal" "config" "PidMode" "host" check_dockerd "notequal" "config" "IpcMode" "host" check_dockerd "notequal" "config" "UsernsMode" "host" check_dockerd "equal" "config" "Devices" "" check_dockerd "equal" "config" "Ulimits" "" check_dockerd "notequal" "config" "Propagation" "shared" check_dockerd "notequal" "config" "UTSMode" "shared" check_ausearch "equal" "docker" "exec" "privileged" "" check_ausearch "equal" "docker" "exec" "user" "" check_dockerd "equal" "config" "CgroupParent" "" check_dockerd "notequal" "config" "PidsLimit" "0" check_dockerd "notequal" "config" "PidsLimit" "-1" for param in NET_ADMIN SYS_ADMIN SYS_MODULE; do check_dockerd unused kernel ${param} done if [ "${audit_mode}" != 2 ]; then docker_check=$( docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: Volumes={{ .Mounts }}' | grep docker.sock ) if [ "${docker_check}" ]; then inc_insecure "Docker socket is mounted inside a container" else inc_secure "Docker socket is not mounted inside a container" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/docker/audit_docker_users.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_docker_users # # Check users in docker group have recently logged in, if not lock them # Warn of any users in group with UID greate than 100 and lock # # Refer to Section(s) 1.4 Page(s) 16-7 CIS Docker Benchmark 1.13.0 # Refer to Section(s) 4.1 Page(s) 105-6 CIS Docker Benchmark 1.13.0 # # Refer to https://github.com/docker/docker/issues/2918 # Refer to https://github.com/docker/docker/pull/4572 # Refer to https://github.com/docker/docker/issues/7906 # Refer to https://www.altiscale.com/hadoop-blog/making-docker-work-yarn/ # Refer to https://docs.docker.com/articles/security/ # Refer to https://docs.docker.com/articles/security/#docker-daemon-attack-surface # Refer to https://www.andreas-jung.com/contents/on-docker-security-docker-group-considered-harmful # Refer to https://www.projectatomic.io/blog/2015/08/why-we-dont-let-non-root-users-run-docker-in-centos-fedora-or-rhel/ #. audit_docker_users () { print_function "audit_docker_users" string="Docker Users" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then docker_bin=$( command -v docker ) if [ "${docker_bin}" ]; then check_file="/etc/group" if [ "${audit_mode}" != 2 ]; then user_list=$( grep "^${docker_group}:" "${check_file}" | cut -f4 -d: | sed 's/,/ /g' ) for user_name in ${user_list}; do last_login=$( last -1 "${user_name}" | grep '[a-z]' | awk '{print $1}' ) if [ "${last_login}" = "wtmp" ]; then if test -r "/etc/shadow"; then lock_test=$( grep "^${user_name}:" /etc/shadow | grep -v 'LK' | cut -f1 -d: ) if [ "${lock_test}" = "${user_name}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "User \"${user_name}\" in group \"${docker_group}\" and has not logged in recently and their account is not locked" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "User \"${user_name}\" to locked" passwd -l "${user_name}" fi else inc_secure "User \"${user_name}\" in group \"${docker_group}\" has not logged in recently and their account is locked" fi fi fi done else restore_file "${check_file}" "${restore_dir}" fi if [ "${audit_mode}" != 2 ]; then user_list=$( grep "^${docker_group}:" "${check_file}" | cut -f4 -d: | sed 's/,/ /g' ) for user_name in ${user_list}; do user_id=$( uid -u "${user_name}" ) if [ "${user_id}" -gt "${max_super_user_id}" ] ; then if test -r "/etc/shadow"; then lock_test=$( grep "^${user_name}:" /etc/shadow | grep -v 'LK' | cut -f1 -d: ) if [ "${lock_test}" = "${user_name}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "User \"${user_name}\" is in group \"${docker_group}\" has and ID greater than \"${max_super_user_id}\" and their account is not locked" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "User \"${user_name}\" to locked" passwd -l "${user_name}" fi else inc_secure "User \"${user_name}\" in group \"${docker_group}\" has an id less than \"${max_super_user_id}\" and their account is locked" fi fi fi done else restore_file "${check_file}" "${restore_dir}" fi if [ "${audit_mode}" != 2 ]; then check_dockerd "notequal" "config" "User" "" fi fi else na_message "${string}" fi } ================================================ FILE: modules/esxi/audit_dcui.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dcui # # Check DCUI # # Refer to http://pubs.vmware.com/vsphere-55/topic/com.vmware.vsphere.security.doc/GUID-6779F098-48FE-4E22-B116-A8353D19FF56.html #. audit_dcui () { print_function "audit_dcui" string="DCUI" check_message "${string}" if [ "${os_name}" = "VMkernel" ]; then service_name="DCUI" verbose_message "${service_name} Lockdown" "check" check_linux_service "${service_name}" "off" backup_file="${work_dir}/dvfilter" command="vim-cmd -U dcui vimsvc/auth/lockdown_is_enabled" command_message "${command}" current_value=$( eval "${command}" ) if [ "${audit_mode}" != "2" ]; then if [ "${current_value}" != "true" ]; then if [ "${audit_mode}" = "0" ]; then echo "${current_value}" > "${backup_file}" set_message "DCUI Lockdown to true" command="vim-cmd -U dcui vimsvc/auth/lockdown_mode_enter" command_message "${command}" eval "${command}" fi if [ "${audit_mode}" = "1" ]; then inc_insecure "DCUI Lockdown is disabled" fix_message "vim-cmd -U dcui vimsvc/auth/lockdown_mode_enter" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "DCUI Lockdown is enabled" fi fi else restore_file="${restore_dir}/$test" if [ -f "${restore_file}" ]; then previous_value=$( cat "${restore_file}" ) if [ "${previous_value}" != "${current_value}" ]; then verbose_message "DCUI Lockdown to ${previous_value}" "restore" if [ "${previous_value}" = "true" ]; then command="vim-cmd -U dcui vimsvc/auth/lockdown_mode_enter" command_message "${command}" eval "${command}" else command="vim-cmd -U dcui vimsvc/auth/lockdown_mode_exit" command_message "${command}" eval "${command}" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/esxi/audit_dvfilter.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dvfilter # # Check Dvfilter # # Refer to http://pubs.vmware.com/vsphere-55/topic/com.vmware.vsphere.ext_solutions.doc/GUID-6013E15D-92CE-4970-953C-ACCB36ADA8AD.html # Refer to http://pubs.vmware.com/vsphere-55/topic/com.vmware.vsphere.security.doc/GUID-CD0783C9-1734-4B9A-B821-ED17A77B0206.html #. audit_dvfilter () { print_function "audit_dvfilter" string="Dvfilter" check_message "${string}" if [ "${os_name}" = "VMkernel" ]; then backup_file="${work_dir}/dvfilter" command="esxcli --formatter=csv --format-param=fields=Path,Int Value system settings advanced list | grep /Net/DVFilterBindIpAddress | cut -f2 -d," command_message "${command}" current_value=$( eval "${command}" ) if [ "${audit_mode}" != "2" ]; then if [ "${current_value}" != "0" ]; then if [ "${audit_mode}" = "0" ]; then echo "${current_value}" > "${backup_file}" set_message "Dvfilter to disabled" command="esxcli system settings advanced set -o /Net/DVFilterBindIpAddress -d" command_message "${command}" eval "${command}" fi if [ "${audit_mode}" = "1" ]; then inc_insecure "Dvfilter enabled" fix_message "esxcli system settings advanced set -o /Net/DVFilterBindIpAddress -d" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Dvfilter disabled" fi fi else restore_file="${restore_dir}/dvfilter" if [ -f "${restore_file}" ]; then previous_value=$( cat "${restore_file}" ) if [ "${previous_value}" != "${current_value}" ]; then restore_message "Dvfilter to \"${previous_value}\"" command="esxcli system settings advanced set -o /Net/DVFilterBindIpAddress -i \"${previous_value}\"" command_message "${command}" eval "${command}" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/esxi/audit_esxi_shell.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_esxi_shell # # Check ESXi Shell # # Refer to http://kb.vmware.com/kb/2004746 # Refer to http://pubs.vmware.com/vsphere-55/topic/com.vmware.vsphere.security.doc/GUID-B5144CE9-F8BB-494D-8F5D-0D5621D65DAE.html #. audit_esxi_shell () { print_function "audit_esxi_shell" string="ESXShell" check_message "${string}" if [ "${os_name}" = "VMkernel" ]; then check_linux_service "ESXShell" "off" else na_message "${string}" fi } ================================================ FILE: modules/esxi/audit_mob.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_mob # # Check Managed Object Browser # # Refer to http://pubs.vmware.com/vsphere-51/index.jsp?topic=%2Fcom.vmware.vsphere.security.doc%2FGUID-0EF83EA7-277C-400B-B697-04BDC9173EA3.html #. audit_mob () { print_function "audit_mob" string="Managed Object Browser" check_message "${string}" if [ "${os_name}" = "VMkernel" ]; then log_file="mob_status" backup_file="${work_dir}/${log_file}" command="vim-cmd proxysvc/service_list | grep \"/mob\" | awk '{print \$3}' | cut -f1 -d, | sed 's/\"//g'" command_message "${command}" current_value=$( eval "${command}" ) if [ "${current_value}" = "/mob" ]; then current_value="enabled" else current_value="disabled" fi if [ "${audit_mode}" != "2" ]; then if [ "${current_value}" != "disabled" ]; then if [ "${audit_mode}" = "0" ]; then if [ "${syslog_server}" != "" ]; then echo "enabled" > "${backup_file}" set_message "Managed Object Browser to disabled" command="vim-cmd proxysvc/remove_service \"/mob\" \"httpsWithRedirect\"" command_message "${command}" eval "${command}" fi fi if [ "${audit_mode}" = "1" ]; then inc_insecure "Managed Object Browser enabled" fix_message "vim-cmd proxysvc/remove_service \"/mob\" \"httpsWithRedirect\"" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Managed Object Browser disabled" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then previous_value=$( cat "${restore_file}" ) if [ "${previous_value}" = "enabled" ]; then restore_message "Managed Object Browser to enabled" command="vim-cmd proxysvc/add_np_service \"/mob\" httpsWithRedirect /var/run/vmware/proxy-mob" command_message "${command}" eval "${command}" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/firewall/audit_firewall_setting.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_firewall_setting # # Apple's firewall will protect your computer from certain incoming attacks. # Apple offers three firewall options: Allow all, Allow only essential, and # Allow access for specific incoming connections. Unless you have a specific # need to allow incoming connection (for services such as SSH, file sharing, # or web services), set the firewall to "Allow only essential services," # otherwise use the "allow access for specific incoming connections" option. # # 0 = off # 1 = on for specific services # 2 = on for essential services # # Refer to Section(s) 2.6.4 Page(s) CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.6.3 Page(s) 56-7 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.2.1-2,3.6 Page(s) 60-9,283-6 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_firewall_setting () { print_function "audit_firewall_setting" string="Firewall Settings" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_int "/Library/Preferences/com.apple.alf" "globalstate" "1" if [ "${audit_mode}" != 2 ]; then command="sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getstealthmode | grep -cE \"enabled|on\" | sed \"s/ //g\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" = "1" ]; then inc_secure "Firewall stealth mode enabled" else inc_insecure "Firewall stealth mode is not enabled" run_lockdown "sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode on" "Stealth mode on" fi command="sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getloggingmode | grep -cE \"enabled|on\" | sed \"s/ //g\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" = "1" ]; then inc_secure "Firewall logging mode enable" else inc_insecure "Firewall logging mode is not enabled" run_lockdown "sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setloggingmode on" "Logging mode on" fi command="sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getloggingopt | grep -c detail | sed \"s/ //g\"" command_message "${command}" check=$( eval "${command}" ) if [ "${check}" = "1" ]; then inc_secure "Firewall logging option detailed" else inc_insecure "Firewall logging option is not detailed" run_lockdown "sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setloggingopt detail" "Logging output detail" fi fi else na_message "${string}" fi } ================================================ FILE: modules/firewall/audit_ipfilter.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ipfilter # # Turn off IP filter #. audit_ipfilter () { print_function "audit_ipfilter" string="IP Filter" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/ipfilter:default" "disabled" check_sunos_service "svc:/network/pfil:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/firewall/audit_ipfw.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ipfw # # Check IP Firewall # # Refer to Section 1.3 Page(s) 3-4 CIS FreeBSD Benchmark v1.0.5 #. audit_ipfw () { print_function "audit_ipfw" string="IP Firewall" check_message "${string}" if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/rc.conf" "firewall_enable" "eq" "YES" "hash" check_file_value "is" "/etc/rc.conf" "firewall_type" "eq" "client" "hash" else na_message "${string}" fi } ================================================ FILE: modules/firewall/audit_ipsec.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ipsec # # Turn off IPSEC #. audit_ipsec () { print_function "audit_ipsec" string="IPSEC Services" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/ipsec/manual-key:default" "disabled" check_sunos_service "svc:/network/ipsec/ike:default" "disabled" check_sunos_service "svc:/network/ipsec/ipsecalgs:default" "disabled" check_sunos_service "svc:/network/ipsec/policy:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/firewall/audit_iptables.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_iptables # # Turn on iptables # # Refer to Section(s) 5.7-8 Page(s) 114-8 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 4.7-8 Page(s) 101-3 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 4.7-8 Page(s) 92-3 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 3.6.1 Page(s) 153-4 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 3.6.1 Page(s) 139-40 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 3.6.1-3 Page(s) 149-52 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_iptables () { print_function "audit_iptables" string="IP Tables" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_linux_package "install" "iptables" check_linux_service "iptables" "on" check_linux_service "ip6tables" "on" if [ "${audit_mode}" != 2 ]; then iptables_check=$( command -v iptables 2> /dev/null ) if [ "${iptables_check}" ]; then if [ "${my_id}" = "0" ]; then command="iptables -L INPUT -v -n | grep \"127.0.0.0\" | grep \"0.0.0.0\" | grep DROP | uniq | wc -l | sed \"s/ //g\"" command_message "${command}" rules_check=$( eval "${command}" ) fi if [ "${rules_check}" = "0" ]; then inc_insecure "All other devices allow trafic to the loopback network" else inc_secure "All other devices deny trafic to the loopback network" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/firewall/audit_routing_daemons.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_routing_daemons # # Turn off routing services if not required # # AIX: # # Refer to Section(s) 1.3.12-3,5 Page(s) 47-50,51-2 CIS AIX Benchmark v1.1.0 #. audit_routing_daemons () { print_function "audit_routing_daemons" string="Routing Daemons" check_message "${string}" if [ "$routed_disable" = "yes" ]; then if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then for service_name in "svc:/network/routing/zebra:quagga" \ "svc:/network/routing/ospf:quagga" \ "svc:/network/routing/rip:quagga" \ "svc:/network/routing/ripng:default" \ "svc:/network/routing/ripng:quagga" \ "svc:/network/routing/ospf6:quagga" \ "svc:/network/routing/bgp:quagga" \ "svc:/network/routing/legacy-routing:ipv4" \ "svc:/network/routing/legacy-routing:ipv6" \ "svc:/network/routing/rdisc:default" \ "svc:/network/routing/route:default" \ "svc:/network/routing/ndp:default"; do check_sunos_service "${service_name}" "disabled" done fi fi if [ "${os_name}" = "Linux" ]; then for service_name in bgpd ospf6d ospfd ripd ripngd; do check_linux_service "${service_name}" "off" done fi fi if [ "${os_name}" = "AIX" ]; then for service_name in gated mrouted routed; do check_rctcp "${service_name}" "off" done fi else na_message "${string}" fi } ================================================ FILE: modules/firewall/audit_routing_params.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_routing_params # # Network Routing # Source Packet Forwarding # Directed Broadcast Packet Forwarding # Response to ICMP Timestamp Requests # Response to ICMP Broadcast Timestamp Requests # Response to ICMP Broadcast Netmask Requests # Response to Broadcast ICMPv4 Echo Request # Response to Multicast Echo Request # Ignore ICMP Redirect Messages # Strict Multihoming # ICMP Redirect Messages # TCP Reverse IP Source Routing # Maximum Number of Half-open TCP Connections # Maximum Number of Incoming Connections # # Refer to Section(s) 3.4-17 Page(s) 28-39 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 3.5 Page(s) 64-5 CIS Solaris 10 Benchmark v5.1.0 #. audit_routing_params () { print_function "audit_routing_params" string="Routing Parameters" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_message "IP Routing" check_command_value "routeadm" "ipv4-routing" "disabled" check_command_value "routeadm" "ipv6-routing" "disabled" check_message "IP Forwarding" check_command_value "routeadm" "ipv4-forwarding" "disabled" check_command_value "routeadm" "ipv6-forwarding" "disabled" check_file_exists "/etc/notrouter" "yes" fi if [ "${os_version}" = "11" ]; then check_message "IP Routing" audit_ipadm_value "_forward_src_routed" "ipv4" "0" audit_ipadm_value "_forward_src_routed" "ipv6" "0" audit_ipadm_value "_rev_src_routes" "tcp" "0" check_message "Broadcasting" audit_ipadm_value "_forward_directed_broadcasts" "ip" "0" audit_ipadm_value "_respond_to_timestamp" "ip" "0" audit_ipadm_value "_respond_to_timestamp_broadcast" "ip" "0" audit_ipadm_value "_respond_to_address_mask_broadcast" "ip" "0" audit_ipadm_value "_respond_to_echo_broadcast" "ip" "0" check_message "Multicasting" audit_ipadm_value "_respond_to_echo_multicast" "ipv4" "0" audit_ipadm_value "_respond_to_echo_multicast" "ipv6" "0" check_message "IP Redirecting" audit_ipadm_value "_ignore_redirect" "ipv4" "1" audit_ipadm_value "_ignore_redirect" "ipv6" "1" audit_ipadm_value "_send_redirects" "ipv4" "0" audit_ipadm_value "_send_redirects" "ipv6" "0" check_message "Multihoming" audit_ipadm_value "_strict_dst_multihoming" "ipv4" "1" audit_ipadm_value "_strict_dst_multihoming" "ipv6" "1" check_message "Queue Sizing" audit_ipadm_value "_conn_req_max_q0" "tcp" "4096" audit_ipadm_value "_conn_req_max_q" "tcp" "1024" fi else na_message "${string}" fi } ================================================ FILE: modules/firewall/audit_suse_firewall.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_suse_firewall # # Check SuSE Firewall enabled # # Refer to Section(s) 7.7 Page(s) 83-4 SLES 11 Benchmark v1.0.0 #. audit_suse_firewall () { print_function "audit_suse_firewall" string="SuSE Firewall" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "SuSE" ]; then check_linux_service "SuSEfirewall2_init" "on" check_linux_service "SuSEfirewall2_setup" "on" fi else na_message "${string}" fi } ================================================ FILE: modules/firewall/audit_ufw.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ufw # # Chec UFW is enabled # # Refer to Section(s) 3.5.1.1-3 Page(s) 216-20 CIS Ubuntu 22.04 Benchmark v1.0.0 # Refer to Section(s) 4.2.1-7 Page(s) 447-56 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_ufw () { print_function "audit_ufw" string="UFW" check_message "${string}" if [ "${os_name}" = "Linux" ] && [ "${os_vendor}" = "Ubuntu" ]; then check_linux_package "install" "ufw" check_linux_service "ufw" "on" check_file_value "is" "/etc/ufw/ufw.conf" "LOGLEVEL" "eq" "high" "hash" check_linux_package "uninstall" "iptables-persistent" else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_autofs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_autofs # # Check Automount services # # Refer to Section(s) 2.9 Page(s) 21 CIS Solaris 11.1 v1.0.0 # Refer to Section(s) 1.1.22 Page(s) 47 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 1.1.21 Page(s) 45 CIS Ubuntu LTS 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.1 Page(s) 228-30 CIS Ubuntu LTS 24.04 Benchmark v1.0.0 # Refer to Section(s) 2.2.10 Page(s) 30 CIS Solaris 10 v5.1.0 # Refer to Section(s) 2.25 Page(s) 31 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.1.19 Page(s) 43 CIS Amazon Linux Benchmark v2.0.0 #. audit_autofs () { print_function "audit_autofs" string="Automount Services" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/system/filesystem/autofs" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "autofs" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_file_extensions.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_file_extensions # # Check File Extensions # # Refer to Section(s) 6.2 Page(s) 77-8 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 6.2 Page(s) 162-3 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 6.1.1 Page(s) 362-4 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_file_extensions() { print_function "audit_file_extensions" string="File Extensions" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_int "NSGlobalDomain" "AppleShowAllExtensions" "1" else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_file_metadata.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_file_metadata # # Check Auditing of File Metadata Modification Events # # Refer to Section(s) 4.3 Page(s) 41-2 CIS Solaris 11.1 Benchmark v1.0.0 #. audit_file_metadata () { print_function "audit_file_metadata" string="Auditing of File Metadata Modification Events" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "11" ]; then check_append_file "/etc/security/audit_event" "lck:AUE_CHMOD" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_CHOWN" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_FCHOWN" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_FCHMOD" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_LCHOWN" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_ACLSET" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_FACLSET" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_file_perms.sh ================================================ #!/bin/sh # -> Needs checking of obase/ibase etc # shellcheck disable=SC1090 # shellcheck disable=SC2012 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # shellcheck disable=SC2216 # audit_file_perms # # It is important to ensure that system files and directories are maintained # with the permissions they were intended to have from the OS vendor (Oracle). #. audit_file_perms () { print_function "audit_file_perms" string="System File Permissions" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then log_file="fileperms.log" if [ "${audit_mode}" != 2 ]; then if [ "${os_version}" = "11" ]; then error=0 command=$( pkg verify | grep file | awk '{print $2}' ) else command=$( pkgchk -n 2>&1 |grep ERROR | awk '{print $2}' ) fi for check_file in ${command}; do if [ "${audit_mode}" = 1 ]; then inc_insecure "Incorrect permissions on file \"${check_file}\"" fi if [ "${audit_mode}" = 0 ]; then if [ "${os_version}" = "10" ]; then verbose_message "Setting: Correct permissions on file \"${check_file}\"" log_file="${work_dir}/${log_file}" command="ls -l \"${check_file}\" | echo \"obase=8;ibase=2;\`awk '{print \$1}' | cut -c2-10 | tr 'xrws-' '11110'\`\" | /usr/bin/bc" command_message "${command}" file_perms=$( eval "${command}" ) command="ls -l \"${check_file}\" | awk '{print \$3\",\"\$4}'" command_message "${command}" file_owner=$( eval "${command}" ) echo "${check_file},${file_perms},${file_owner}" >> "${log_file}" pkgchk -f -n -p "${file_name}" 2> /dev/null else error=1 fi fi done if [ "${os_version}" = "11" ]; then if [ "${audit_mode}" = 0 ]; then if [ "$error" = 1 ]; then log_file="${work_dir}/${log_file}" command="ls -l \"${check_file}\" | echo \"obase=8;ibase=2;\`awk '{print \$1}' | cut -c2-10 | tr 'xrws-' '11110'\`\" | /usr/bin/bc" command_message "${command}" file_perms=$( eval "${command}" ) command="ls -l \"${check_file}\" | awk '{print \$3\",\"\$4}'" command_message "${command}" file_owner=$( eval "${command}" ) echo "${check_file},${file_perms},${file_owner}" >> "${log_file}" pkg fix fi fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then restore_check=$( grep "${check_file}" "${restore_file}" | cut -f1 -d, ) if [ "$restore_check" = "${check_file}" ]; then restore_info=$( grep "${check_file}" "${restore_file}" ) restore_perms=$( echo "${restore_info}" | cut -f2 -d, ) restore_owner=$( echo "${restore_info}" | cut -f3 -d, ) restore_group=$( echo "${restore_info}" | cut -f4 -d, ) verbose_message "Restoring: File ${check_file} to previous permissions" chmod "${restore_perms}" "${check_file}" if [ "${restore_owner}" != "" ]; then chown "${restore_owner}:${restore_group}" "${check_file}" fi fi fi fi fi if [ "${os_name}" = "Linux" ]; then verbose_message "System File Permissions" log_file="fileperms.log" if [ "${audit_mode}" != 2 ]; then verbose_message "File permissions [This may take a while]" # Check specific to Debian if [ "${os_vendor}" = "Ubuntu" ] || [ "${os_vendor}" = "Debian" ]; then # TODO echo "" fi # Check specific to Red Hat/CentOS if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ]; then file_list=$( rpm -Va --nomtime --nosize --nomd5 --nolinkt | awk '{print $2}' ) for check_file in ${file_list}; do if [ "${audit_mode}" = 1 ]; then inc_insecure "Incorrect permissions on ${file_name}" verbose_message "yum reinstall ${rpm_name}" "fix" fi if [ "${audit_mode}" = 0 ]; then verbose_message "Setting: Correct permissions on file \"${file_name}\"" log_file="${work_dir}/${log_file}" file_perms=$( stat -c %a "${check_file}" ) file_owner=$( ls -l "${check_file}" | awk '{print $3","$4}' ) echo "${check_file},${file_perms},${file_owner}" >> "${log_file}" yum reinstall "${rpm_name}" fi done fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then restore_check=$( grep "${check_file}" "${restore_file}" | cut -f1 -d, ) if [ "$restore_check" = "${check_file}" ]; then restore_info=$( grep "${check_file}" "${restore_file}" ) restore_perms=$( echo "${restore_info}" | cut -f2 -d, ) restore_owner=$( echo "${restore_info}" | cut -f3 -d, ) restore_group=$( echo "${restore_info}" | cut -f4 -d, ) verbose_message "Restoring: File \"${check_file}\" to previous permissions" chmod "${restore_perms}" "${check_file}" if [ "${restore_owner}" != "" ]; then chown "${restore_owner}:${restore_group}" "${check_file}" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_hotplug.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_hotplug # # Turn off hotplug #. audit_hotplug () { print_function "audit_hotplug" string="Hotplug Service" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/system/hotplug:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then for service_name in pcscd haldaemon kudzu; do check_linux_service "${service_name}" "off" done fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_nfs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_nfs # # Check NFS # # Refer to Section(s) 3.8 Page(s) 64-5 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.8 Page(s) 77 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.8 Page(s) 67-8 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.7 Page(s) 107 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.7 Page(s) 57-8 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 3.7-11 Page(s) 11-3 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.3.5 Page(s) 39 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 2.2.7 Page(s) 99 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.7 Page(s) 107 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.9,12 Page(s) 251-3,60-2 CIS Ubuntu 24.04 Benchmark v1.0.0 # Refer to Section(s) 4.6 Page(s) 105-6 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 4.3 Page(s) 294-5 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_nfs () { print_function "audit_nfs" string="NFS Services" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ] || [ "${os_name}" = "Darwin" ]; then if [ "$nfsd_disable" = "yes" ]; then if [ "${os_name}" = "AIX" ]; then check_itab "rcnfs" "off" fi if [ "${os_name}" = "Darwin" ]; then check_launchctl_service "com.apple.nfsd" "off" fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then for service_name in "svc:/network/nfs/mapid:default" \ "svc:/network/nfs/status:default" "svc:/network/nfs/cbd:default" \ "svc:/network/nfs/nlockmgr:default" "svc:/network/nfs/client:default" \ "svc:/network/nfs/server:default"; do check_sunos_service "${service_name}" "disabled" done fi if [ "${os_version}" != "11" ]; then check_sunos_service "nfs.server" "disabled" fi check_file_value "is" "/etc/system" "nfssrv:nfs_portmon" "eq" "1" "star" fi if [ "${os_name}" = "Linux" ]; then for service_name in nfs nfslock rpc nfs-kerner-server rpcbind; do check_linux_service "${service_name}" "off" done fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/rc.conf" "nfs_reserved_port_only" "eq" "YES" "hash" check_file_value "is" "/etc/rc.conf" "weak_mountd_authentication" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "rpc_lockd_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "rpc_statd_enable" "eq" "NO" "hash" if [ "${os_version}" -lt 5 ]; then check_file_value "is" "/etc/rc.conf" "portmap_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "nfs_server_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "single_mountd_enable" "eq" "NO" "hash" else check_file_value "is" "/etc/rc.conf" "rpcbind_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "nfs_server_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "mountd_enable" "eq" "NO" "hash" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_samba.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_samba # # Check Samba settings # # Refer to Section(s) 3.13 Page(s) 68 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.13 Page(s) 80 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.2.12 Page(s) 112 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.12 Page(s) 60-1 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.4.14.4 Page(s) 55 CIS OS X 10.5 Benchmark v1.1.0 # Refer to Section(s) 2.2.9 Page(s) 29-30 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 2.2.12-3 Page(s) 104-5 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.12-3 Page(s) 112-3 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_samba () { print_function "audit_samba" string="Samba Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then if [ "${os_update}" -ge 4 ]; then check_sunos_service "svc:/network/samba" "disabled" else check_sunos_service "samba" "disabled" fi fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "smb" "off" check_linux_package "uninstall" "samba" fi for check_dir in /etc /etc/sfw /etc/samba /usr/local/etc /usr/sfw/etc /opt/sfw/etc; do check_file="${check_dir}/smb.conf" if [ -f "${check_file}" ]; then check_file_value_with_position "is" "${check_file}" "restrict anonymous" "eq" "2" "semicolon" "after" "\[Global\]" check_file_value_with_position "is" "${check_file}" "guest OK" "eq" "no" "semicolon" "after" "\[Global\]" check_file_value_with_position "is" "${check_file}" "client ntlmv2 auth" "eq" "yes" "semicolon" "after" "\[Global\]" fi done else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_setup_file.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_setup_file # # Check Setup File permissions #. audit_setup_file () { print_function "audit_setup_file" string="Setup file" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_file_perms "/var/db/.AppleSetupDone" "0400" "root" "${wheel_group}" else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_smbconf_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC2034 # shellcheck disable=SC1090 # shellcheck disable=SC2154 # audit_smbconf_perms # # Check SMB config permissions # # Refer to Section(s) 11.2-3 Page(s) 143-4 CIS Solaris 10 Benchmark v1.1.0 #. audit_smbconf_perms () { print_function "audit_smbconf_perms" string="SMB Config Permissions" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_perms "/etc/samba/smb.conf" "0644" "root" "root" else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_sticky_bit.sh ================================================ #!/bin/sh # shellcheck disable=SC2034 # shellcheck disable=SC1090 # shellcheck disable=SC2154 # audit_sticky_bit # # Check sticky bits set of files # # Refer to Section(s) 1.17 Page(s) 26 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.1.21 Page(s) 46 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 1.1.17 Page(s) 28 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.1.17 Page(s) 27 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.17 Page(s) 26 CIS SLES 11 Benchmark v1.2.0 # Refer to Section(s) 6.3 Page(s) 21-22 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 5.3 Page(s) 77-8 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 1.1.18 Page(s) 42 CIS Amazon Linux Benchmark v2.0.0 #. audit_sticky_bit () { print_function "audit_sticky_bit" string="World Writable Directories and Sticky Bits" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${do_fs}" = 1 ]; then if [ "${os_version}" = "10" ]; then log_file="sticky_bits" file_list=$( find / \( -fstype nfs -o -fstype cachefs \ -o -fstype autofs -o -fstype ctfs \ -o -fstype mntfs -o -fstype objfs \ -o -fstype proc \) -prune -o -type d \ \( -perm -0002 -a -perm -1000 \) -print ) for check_dir in ${file_list}; do lock_command="sudo chmod +t ${check_dir}" if [ "${audit_mode}" = 1 ]; then inc_insecure "Sticky bit not set on \"${check_dir}\"" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${check_dir}" set_message "Sticky bit on \"${check_dir}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string} on ${check_dir}" echo " command: sh -c \"sudo chmod +t ${check_dir}\"" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" else lock_message="Sticky bit from \"${check_dir}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi done if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/sticky_bits" if [ -f "${restore_file}" ]; then check_dirs=$( cat "${restore_file}" ) for check_dir in ${check_dirs}; do if [ -d "${check_dir}" ]; then restore_command="sudo chmod -t ${check_dir}" restore_message="Removing sticky bit from \"${check_dir}\"" execute_restore "${restore_command}" "${restore_message}" "sudo" fi done fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_suid_files.sh ================================================ #!/bin/sh # shellcheck disable=SC1083 # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_suid_files # # Check Set UID/GID on files # # Refer to Section(s) 9.1.13-4 Page(s) 161-2 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.1.13-4 Page(s) 186-7 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.1.13-4 Page(s) 164-5 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.1.12-4 Page(s) 272-4 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 12.11-12 Page(s) 152-3 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 6.5 Page(s) 22 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.16.1 Page(s) 231-2 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9.23 Page(s) 88-9 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.1.12-4 Page(s) 250-2 CIS Amazon Linux Benchmark v1.0.0 # Refer to Section(s) 6.1.13-4 Page(s) 264-5 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 7.1.13 Page(s) 961-3 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_suid_files () { print_function "audit_suid_files" string="Set UID/GID Files" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then log_file="setuidfiles.log" if [ "${audit_mode}" = 1 ]; then if [ "${os_name}" = "Linux" ]; then command="df --local -P | awk {'if (NR!=1) print \$6'}" command_message "${command}" file_systems=$( eval "${command}" ) for file_system in ${file_systems}; do command="find \"${file_system}\" -xdev -type f -perm -4000 -print 2> /dev/null" command_message "${command}" check_files=$( eval "${command}" ) for check_file in ${check_files}; do inc_insecure "File \"${check_file}\" is SUID/SGID" lock_command="chmod o-S \"${check_file}\"" lock_message="Setting file \"${check_file}\" to be non world writable" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking write permissions for \"${check_file}\"" echo " file:" echo " path: \"${check_file}\"" echo " mode: o-S" echo "" fi if [ "${audit_mode}" = 1 ]; then inc_insecure "File \"${check_file}\" is world writable" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi if [ "${audit_mode}" = 0 ]; then echo "${check_file}" >> "${log_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi done done else if [ "${os_name}" = "SunOS" ]; then find_command="find / \( -fstype nfs -o -fstype cachefs \ -o -fstype autofs -o -fstype ctfs -o -fstype mntfs \ -o -fstype objfs -o -fstype proc \) -prune \ -o -type f \( -perm -4000 -o -perm -2000 \) -print" fi if [ "${os_name}" = "AIX" ]; then find_command="find / \( -fstype jfs -o -fstype jfs2 \) \ \( -perm -04000 -o -perm -02000 \) -typ e f -ls" fi lock_command="chmod o-S ${check_file}" lock_message="Setting file \"${check_file}\" to be non world writable" for check_file in $( ${find_command} ); do inc_insecure "File ${check_file} is SUID/SGID" if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking write permissions for ${check_file}" echo " file:" echo " path: ${check_file}" echo " mode: o-S" echo "" fi if [ "${audit_mode}" = 1 ]; then inc_insecure "File \"${check_file}\" is world writable" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi done fi fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_unowned_files.sh ================================================ #!/bin/sh # shellcheck disable=SC1083 # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_unowned_files # # Find unowned files # # Refer to Section(s) 9.1.11-2 Page(s) 160-1 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.1.11-2 Page(s) 184-6 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.1.11-2 Page(s) 163-4 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.1.11-2 Page(s) 270-1 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 12.9-10 Page(s) 151-2 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 6.7 Page(s) 23 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.16.2 Page(s) 232-3 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9.24 Page(s) 89-90 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.24 Page(s) 135-6 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.1.11-2 Page(s) 248-9 CIS Amazon Linux Benchmark v1.0.0 # Refer to Section(s) 6.1.11-2 Page(s) 262-3 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 7.1.12 Page(s) 958-60 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_unowned_files () { print_function "audit_unowned_files" string="Unowned Files and Directories" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${audit_mode}" = 1 ]; then if [ "${os_name}" = "Linux" ]; then command="df --local -P | awk {'if (NR!=1) print \$6'}" command_message "${command}" file_systems=$( eval "${command}" ) for file_system in ${file_systems}; do command="find \"${file_system}\" -xdev -nouser -ls 2> /dev/null" command_message "${command}" check_files=$( eval "${command}" ) for check_file in ${check_files}; do inc_insecure "File \"${check_file}\" is unowned" done done else if [ "${os_name}" = "SunOS" ]; then find_command="find / \( -fstype nfs -o -fstype cachefs \ -o -fstype autofs -o -fstype ctfs -o -fstype mntfs \ -o -fstype objfs -o -fstype proc \) -prune \ -o \( -nouser -o -nogroup \) -print" fi if [ "${os_name}" = "AIX" ]; then find_command="find / \( -fstype jfs -o -fstype jfs2 \) \ \( -type d -o -type f \) \( -nouser -o -nogroup \) -ls" fi check_files=$( eval "${find_command}" ) for check_file in ${check_file}s; do inc_insecure "File \"${check_file}\" is unowned" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_user_dotfiles.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_user_dotfiles # # Check permissions on user dot file # # Refer to Section(s) 9.2.8 Page(s) 167-168 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.2.10 Page(s) 284 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 9.2.8 Page(s) 193-4 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 13.8 Page(s) 159 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 7.2 Page(s) 25 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 9.8 Page(s) 77-8 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.8 Page(s) 122 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.10 Page(s) 262 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.10 Page(s) 276 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 7.2.10 Page(s) 986-92 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_user_dotfiles () { print_function "audit_user_dotfiles" string="User Dot Files" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi home_dirs=$( grep -v "^/$" < /etc/passwd | cut -f6 -d:) for home_dir in ${home_dirs}; do command="find \"${home_dir}\" -depth 1 -name \".[A-Za-z0-9]*\" 2>/dev/null" command_message "${command}" file_list=$( eval "${command}" ) for check_file in ${file_list}; do if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0600" "" "" fi done done else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_user_netrc.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_user_netrc # # Check for netrc files # # Refer to Section(s) 9.2.9 Page(s) 168-169 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.9,20 Page(s) 194-5,205-6 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.9 Page(s) 171-2 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.2.13-4 Page(s) 286-8 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 13.9,18 Page(s) 160-1,167 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 6.2.13-4 Page(s) 265-7 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 7.2 Page(s) 25 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.5.1 Page(s) 101-2 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9.9,20 Page(s) 78-9,86 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.9,20 Page(s) 122-3,132-3 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 7.2.10 Page(s) 986-92 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_user_netrc () { print_function "audit_user_netrc" string="User Netrc Files" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi check_fail=0 command="grep -v '^/$' < /etc/passwd | cut -f6 -d':'" command_message "${command}" home_dirs=$( eval "${command}" ) for home_dir in ${home_dirs}; do check_file="${home_dir}/.netrc" if [ -f "${check_file}" ]; then check_fail=1 check_file_perms "${check_file}" "0600" fi done if [ "${check_fail}" != 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "No user netrc files exist" else inc_insecure "User netrc files exist" fi fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_user_rhosts.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_user_rhosts # # Check for rhosts files # # Refer to Section(s) 9.2.10 Page(s) 169-70 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.10 Page(s) 195-6 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.10 Page(s) 172-3 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.2.14 Page(s) 289 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 13.10 Page(s) 161 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 7.2 Page(s) 25 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.5.1 Page(s) 101-2 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9.10 Page(s) 79 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.10 Page(s) 124 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.14 Page(s) 267-8 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.14 Page(s) 281 CIS Ubuntu 16.04 Benchmark v2.0.0 # Refer to Section(s) 7.2.10 Page(s) 986-92 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_user_rhosts () { print_function "audit_user_rhosts" string="User RHosts Files" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then check_fail=0 command="grep -v '^/$' < /etc/passwd | cut -f6 -d':'" command_message "${command}" home_dirs=$( eval "${command}" ) for home_dir in ${home_dirs}; do check_file="${home_dir}/.rhosts" if [ -f "${check_file}" ]; then check_fail=1 check_file_exists "${check_file}" "no" fi done if [ "${check_fail}" != 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "No user rhosts files exist" else inc_insecure "User rhosts files exist" fi fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_winbind.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_winbind # # Turn off winbind if not required #. audit_winbind () { print_function "audit_winbind" string="Winbind Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/winbind:default" "disabled" fi if [ "${os_name}" = "Linux" ]; then check_linux_service "winbind" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/fs/audit_writable_files.sh ================================================ #!/bin/sh # shellcheck disable=SC1083 # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_writable_files # # Refer to Section(s) 9.1.10 Page(s) 159-160 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.1.10 Page(s) 183-4 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.1.10 Page(s) 162-3 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.1.10 Page(s) 269 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 12.8 Page(s) 150-1 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 6.1.10 Page(s) 247 CIS Amazon Linux Benchmark v1.0.0 # Refer to Section(s) 6.4 Page(s) 22 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.16.3 Page(s) 233-4 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 5.1,9.22 Page(s) 45,88 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.22 Page(s) 134 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.1.10 Page(s) 261 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 7.1.11 Page(s) 954-7 CIS Ubuntu 24.04 Benchmark v1.0.0 # Refer to Section(s) 5.1.3-4 Page(s) 110-1 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 5.1.7 Page(s) 311-4 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_writable_files () { print_function "audit_writable_files" string="World Writable Files" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${do_fs}" = 1 ]; then log_file="worldwritablefiles.log" if [ "${audit_mode}" = 0 ]; then log_file="${work_dir}/${log_file}" fi if [ "${audit_mode}" != 2 ]; then if [ "${os_name}" = "Linux" ]; then command="df --local -P | awk {'if (NR!=1) print \$6'} 2> /dev/null" command_message "${command}" file_systems=$( eval "${command}" ) for file_system in ${file_systems}; do command="find \"${file_system}\" -xdev -type f -perm -0002 2> /dev/null" command_message "${command}" check_files=$( eval "${command}" ) for check_file in ${check_files}; do if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking write permissions for ${check_file}" echo " file:" echo " path: ${check_file}" echo " mode: o-w" echo "" fi if [ "${audit_mode}" = 1 ]; then inc_insecure "File ${check_file} is world writable" fix_message "chmod o-w ${check_file}" fi if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${check_file}" lock_message="File \"${check_file}\" to be non world writable" lock_command="chmod o-w ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi done done else if [ "${os_name}" = "SunOS" ]; then find_command="find / \( -fstype nfs -o -fstype cachefs \ -o -fstype autofs -o -fstype ctfs -o -fstype mntfs \ -o -fstype objfs -o -fstype proc \) -prune \ -o -type f -perm -0002 -print" fi if [ "${os_name}" = "AIX" ]; then find_command="find / \( -fstype jfs -o -fstype jfs2 \) \ \( -type d -o -type f \) -perm -o+w -ls" fi if [ "${os_name}" = "FreeBSD" ]; then find_command="find / \( -fstype ufs -type file -perm -0002 \ -a ! -perm -1000 \) -print" fi for check_file in $( ${find_command} ); do if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking write permissions for ${check_file}" echo " file:" echo " path: ${check_file}" echo " mode: o-w" echo "" fi if [ "${audit_mode}" = 1 ]; then inc_insecure "File ${check_file} is world writable" fix_message "chmod o-w ${check_file}" fi if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${check_file}" lock_message="File \"${check_file}\" to be non world writable" lock_command="chmod o-w ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi done fi fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then check_files=$( cat "${restore_file}" ) for check_file in ${check_file}s; do if [ -f "${check_file}" ]; then restore_message="File \"${check_file}\" to previous permissions" restore_command="chmod o+w ${check_file}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi done fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/ftp/audit_ftp_banner.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ftp_banner # # Refer to Section(s) 2.12.11 Page(s) 215-6 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 8.4 Page(s) 70-1 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 8.4 Page(s) 114 CIS Solaris 10 Benchmark v5.1.0 #. audit_ftp_banner () { print_function "audit_ftp_banner" string="FTP Warning Banner" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then package_name="bos.msg.${language_suffix}.net.tcp.client" check_lslpp "${package_name}" if [ "${lslpp_check}" = "${package_name}" ]; then message_file="/usr/lib/nls/msg/${language_suffix}/ftpd.cat" command="dspcat -g \"${message_file}\" | grep \"^9[[:blank:]]\" | awk '{print \$3}'" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${audit_mode}" != 2 ]; then if [ "${actual_value}" != "Authorised" ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "FTP warning message isn't enabled" fix_message "dspcat -g \"${message_file}\" > \"${temp_dir}/ftpd.tmp\"" fix_message "sed \"s/\"\%s FTP server (\%s) ready.\"/\"\%s Authorised uses only. All activity may be monitored and reported\"/\" \"${temp_dir}/ftpd.tmp\" > \"${temp_dir}/ftpd.msg\"" fix_message "gencat \"${message_file}\" \"${temp_dir}/ftpd.msg\"" fix_message "rm \"${temp_dir}/ftpd.tmp\" \"${temp_dir}/ftpd.msg\"" fi if [ "${audit_mode}" = 0 ]; then backup_file "${message_file}" command="dspcat -g \"${message_file}\" > \"${temp_dir}/ftpd.tmp\"" command_message "${command}" eval "${command}" sed "s/\"\%s FTP server (\%s) ready.\"/\"\%s Authorised uses only. All activity may be monitored and reported\"/" "${temp_dir}/ftpd.tmp" > "${temp_dir}/ftpd.msg" command="gencat \"${message_file}\" \"${temp_dir}/ftpd.msg\"" command_message "${command}" eval "${command}" command="rm \"${temp_dir}/ftpd.tmp\" \"${temp_dir}/ftpd.msg\"" command_message "${command}" eval "${command}" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "FTP warning message enabled" fi fi else restore_file "${message_file}" "${restore_dir}" fi else verbose_message "Package \"${package_name}\" is not installed" fix fi fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file="/etc/ftpd/banner.msg" check_file_value is "${check_file}" Authorised space "users only" hash if [ "${audit_mode}" = 0 ]; then check_file_perms "${check_file}" 0444 root root fi fi if [ "${os_version}" = "11" ]; then check_file="/etc/proftpd.conf" check_file_value is "${check_file}" DisplayConnect space /etc/issue hash if [ "${audit_mode}" = 0 ]; then svcadm restart ftp fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/ftp/audit_ftp_client.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ftp_client # # Refer to Section(s) 2.2.6 Page(s) 302-3 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_ftp_client () { print_function "audit_ftp_client" string="FTP Client" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for package in ftp tnftp; do check_linux_package "uninstall" "${package}" done else na_message "${string}" fi } ================================================ FILE: modules/ftp/audit_ftp_conf.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ftp_conf # # Audit FTP Configuration #. audit_ftp_conf () { print_function "audit_ftp_conf" string="FTP users" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then audit_ftp_users "/etc/ftpusers" fi if [ "${os_name}" = "SunOS" ]; then audit_ftp_users "/etc/ftpd/ftpusers" fi if [ "${os_name}" = "Linux" ]; then audit_ftp_users "/etc/vsftpd/ftpusers" fi else na_message "${string}" fi } ================================================ FILE: modules/ftp/audit_ftp_logging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ftp_logging # # Check FTP logging # # Refer to Section(s) 4.2 Page(s) 67 CIS Solaris 10 Benchmark v5.1.0 #. audit_ftp_logging () { print_function "audit_ftp_logging" string="FTPD Daemon Logging" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then get_command="svcprop -p inetd_start/exec svc:/network/ftp:default" check_value=$( ${get_command} | grep -c "\-d" ) file_header="ftpd_logging" if [ "${audit_mode}" != 2 ]; then check_message "File ${file_header}" fi log_file="${work_dir}/${file_header}.log" if [ "${audit_mode}" = 1 ]; then if [ "${check_value}" -eq 0 ]; then inc_insecure "FTP daemon logging not enabled" fix_message "inetadm -m svc:/network/ftp exec=\"/usr/sbin/in.ftpd -a -l -d\"" else inc_secure "FTP daemon logging enabled" fi else if [ "${audit_mode}" = 0 ]; then if [ "${check_value}" -eq 0 ]; then set_message "FTP daemon logging to enabled" eval "${get_command} > ${log_file}" eval "inetadm -m svc:/network/ftp exec=\"/usr/sbin/in.ftpd -a -l -d\"" fi else if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${file_header}.log" if [ -f "${restore_file}" ]; then exec_string=$( cat "${restore_file}" ) restore_message "Previous value for FTP daemon to \"${exec_string}\"" evel "inetadm -m svc:/network/ftp exec=\"${exec_string}\"" fi fi fi fi fi fi if [ "${os_name}" = "Linux" ]; then check_file="/etc/vsftpd.conf" if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "log_ftp_protocol" "eq" "YES" "hash" check_file_value "is" "${check_file}" "ftpd_banner" "eq" "Authorized users only. All activity may be monitored and reported." "hash" check_file_perms "${check_file}" "0600" "root" "root" fi check_file="/etc/vsftpd/vsftpd.conf" if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "log_ftp_protocol" "eq" "YES" "hash" check_file_value "is" "${check_file}" "ftpd_banner" "eq" "Authorized users only. All activity may be monitored and reported." "hash" check_file_perms "${check_file}" "0600" "root" "root" fi fi else na_message "${string}" fi } ================================================ FILE: modules/ftp/audit_ftp_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ftp_server # # Turn off ftp server # # Refer to Section(s) 3.10 Page(s) 66 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.10 Page(s) 78-9 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.10 Page(s) 68-9 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.9 Page(s) 109 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 2.2.9 Page(s) 101 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.9 Page(s) 109 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.6 Page(s) 242-4 CIS Ubuntu 24.04 Benchmark v1.0.0 # Refer to Section(s) 4.5 Page(s) 103-4 CIS Apple OS X 10.12 Benchmark v1.0.0 #. audit_ftp_server () { print_function "audit_ftp_server" string="FTP Server" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/ftp:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "vsftpd" "off" check_linux_package "uninstall" "vsftpd" fi if [ "${os_name}" = "Darwin" ]; then check_launchctl "ftp" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/ftp/audit_ftp_umask.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ftp_umask # # Check FTP umask # # Refer to Section(s) 2.12.10 Page(s) 214-5 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 7.4 Page(s) 65-6 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 7.7 Page(s) 106-7 CIS Solaris 10 Benchmark v5.1.0 #. audit_ftp_umask () { print_function "audit_ftp_umask" string="Default umask for FTP Users" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_file_value "is" "/etc/inetd.conf" "/usr/sbin/ftpd" "space" "ftpd -l -u077" "hash" fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file_value "is" "/etc/ftpd/ftpaccess" "defumask" "space" "077" "hash" fi if [ "${os_version}" = "11" ]; then check_file_value "is" "/etc/proftpd.conf" "Umask" "space" "027" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/ftp/audit_ftp_users.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ftp_users # # Check FTP users # # Refer to Section(s) 2.12.9 Page(s) 213-4 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 6.9 Page(s) 52-3 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.5 Page(s) 89-91 CIS Solaris 10 Benchmark v5.1.0 #. audit_ftp_users () { print_function "audit_ftp_users" string="FTP Users" check_message "${string}" check_file="${1}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then for user_name in $( lsuser -c ALL | grep -v ^#name | grep -v root | cut -f1 -d: ); do command="lsuser -f \"${user_name}\" | grep id | cut -f2 -d=" command_message "${command}" user_check=$( eval "${command}" ) if [ "${user_check}" -lt 200 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "User \"${user_name}\" not in \"${check_file}\"" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "User \"${user_name}\" to not be allowed ftp access" check_append_file "${check_file}" "${user_name}" "hash" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "User \"${user_name}\" in \"${check_file}\"" fi fi done if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi fi if [ "${os_name}" = "SunOS" ]; then for user_name in adm bin daemon gdm listen lp noaccess \ nobody nobody4 nuucp postgres root smmsp svctag \ sys uucp webserverd; do command="cut -f1 -d:< /etc/passwd | grep \"^${user_name}$\"" command_message "${command}" user_check=$( eval "${command}" ) user_check=$( expr "${user_check}" : "[A-z]" ) if [ "${user_check}" = 1 ]; then command="grep -v '^#' < \"${check_file}\" | grep \"^${user_name}$\"" command_message "${command}" ftpuser_check=$( eval "${command}" ) ftpuser_check=$( expr "${ftpuser_check}" : "[A-z]" ) if [ "${ftpuser_check}" != 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "User \"${user_name}\" not in \"${check_file}\"" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "User \"${user_name}\" to not be allowed ftp access" check_append_file "${check_file}" "${user_name}" "hash" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "User \"${user_name}\" in \"${check_file}\"" fi fi fi done if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi fi if [ "${os_name}" = "Linux" ]; then for user_name in root bin daemon adm lp sync shutdown halt mail \ news uucp operator games nobody; do command="cut -f1 -d:< /etc/passwd | grep \"^${user_name}$\"" command_message "${command}" user_check=$( eval "${command}" ) user_check=$( expr "${user_check}" : "[A-z]" ) if [ "${user_check}" = 1 ]; then command="grep -v '^#' < \"${check_file}\" | grep \"^${user_name}$\"" command_message "${command}" ftpuser_check=$( eval "${command}" ) ftpuser_check=$( expr "${ftpuser_check}" : "[A-z]" ) if [ "${ftpuser_check}" != 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "User \"${user_name}\" not in \"${check_file}\"" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "User \"${user_name}\" to not be allowed ftp access" check_append_file "${check_file}" "${user_name}" "hash" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "User \"${user_name}\" in \"${check_file}\"" fi fi fi done if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi fi else na_message "${string}" fi } ================================================ FILE: modules/ftp/audit_tftp_client.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_tftp_client # # Turn off TFTP # # Refer to Section(s) 2.1.7 Page(s) 51 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.7 Page(s) 59 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.7 Page(s) 54-5 CIS RHEL 6 Benchmark v1.2.0 #. audit_tftp_client () { print_function "audit_tftp_client" string="TFTP Client" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ]; then check_linux_package "uninstall" "tftp" fi else na_message "${string}" fi } ================================================ FILE: modules/ftp/audit_tftp_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_tftp_server # # Turn off tftp # # Refer to Section(s) 2.1.8 Page(s) 52 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.8 Page(s) 60 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.2.20 Page(s) 121 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.1.8 Page(s) 45 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 6.9 Page(s) 58-9 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.1.16 Page(s) 270-2 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_tftp_server () { print_function "audit_tftp_server" string="TFTP Server" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_file_perms "/tftpboot" "0744" "root" "root" check_file_perms "/etc/netboot" "0744" "root" "root" check_sunos_service "svc:/network/tftp/udp6:default" "disabled" check_sunos_service "svc:/network/tftp/udp4:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "tftp" "off" check_file_perms "/tftpboot" "0744" "root" "root" check_file_perms "/var/tftpboot" "0744" "root" "root" if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "Amazon" ]; then check_linux_service "tftp.socket" "off" check_linux_package "uninstall" "tftp-server" fi fi else na_message "${string}" fi } ================================================ FILE: modules/full/full_audit_accounting_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_accounting_services # # Audit accounting services #. full_audit_accounting_services() { print_function "full_audit_accounting_services" audit_system_accounting audit_process_accounting audit_audit_class audit_sar_accounting audit_prelink audit_aide } ================================================ FILE: modules/full/full_audit_disk_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_disk_services # # Audit disk and hardware related services #. full_audit_disk_services () { print_function "full_audit_disk_services" audit_svm audit_svm_gui audit_iscsi } ================================================ FILE: modules/full/full_audit_file_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_file_services # # Audit file permissions #. full_audit_file_services () { print_function "full_audit_file_services" audit_syslog_perms audit_volfs audit_autofs audit_dfstab audit_mount_setuid audit_mount_nodev audit_mount_noexec audit_mount_fdi audit_nfs audit_uucp audit_cd_sharing audit_filesystem_partitions } ================================================ FILE: modules/full/full_audit_firewall_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_firewall_services # # Audit firewall related services #. full_audit_firewall_services () { print_function "full_audit_firewall_services" audit_ipsec audit_ipfilter audit_tcp_wrappers audit_iptables audit_ipfw audit_suse_firewall } ================================================ FILE: modules/full/full_audit_ftp_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_ftp_services # # Audit FTP Services full_audit_ftp_services () { print_function "full_audit_ftp_services" audit_ftp_logging audit_ftp_umask audit_ftp_conf audit_ftp_client audit_ftp_server audit_tftp_server audit_ftp_banner } ================================================ FILE: modules/full/full_audit_hardware_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_hardware_services # # Audit hardware related services #. full_audit_hardware_services () { print_function "full_audit_hardware_services" audit_hotplug } ================================================ FILE: modules/full/full_audit_kernel_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_kernel_services # # Audit kernel services #. full_audit_kernel_services () { print_function "full_audit_kernel_services" audit_sysctl #audit_kernel_modules audit_kernel_accounting audit_kernel_params audit_tcp_syn_cookie audit_stack_protection audit_tcp_strong_iss audit_routing_params audit_modprobe_conf audit_unconfined_daemons audit_selinux audit_execshield audit_apparmor audit_virtual_memory audit_ptrace_scope } ================================================ FILE: modules/full/full_audit_log_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_log_services # # Audit log files and log related services #. full_audit_log_services () { print_function "full_audit_log_services" audit_syslog_server audit_linux_logfiles audit_syslog_conf audit_debug_logging audit_syslog_auth audit_core_dumps audit_cron_logging audit_logrotate } ================================================ FILE: modules/full/full_audit_mail_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_mail_services # # Audit sendmail full_audit_mail_services () { print_function "full_audit_mail_services" audit_sendmail_daemon audit_sendmail_greeting audit_sendmail_aliases audit_email_daemons audit_postfix_daemon audit_exim } ================================================ FILE: modules/full/full_audit_naming_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_naming_services # # Audit Naming Services #. full_audit_naming_services () { print_function "full_audit_naming_services" audit_nis_server audit_nis_client audit_nisplus audit_ldap_cache audit_kerberos_tgt audit_gss audit_keyserv audit_dns_client audit_dns_server audit_krb5 audit_nis_entries audit_avahi_server audit_avahi_conf } ================================================ FILE: modules/full/full_audit_network_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_network_services # # Audit Network Service #. full_audit_network_services () { print_function "full_audit_network_services" audit_snmp audit_ntp audit_ipmi audit_echo audit_ocfserv audit_tname audit_service_tags audit_ticotsord audit_boot_server audit_slp audit_tnd audit_nobody_rpc audit_dhcpcd audit_dhcprd audit_dhcpsd audit_mob audit_dvfilter audit_wireless audit_ufw } ================================================ FILE: modules/full/full_audit_osx_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_osx_services # # Audit All System #. full_audit_osx_services () { print_function "full_audit_osx_services" audit_bluetooth audit_guest_sharing audit_file_sharing audit_web_sharing audit_login_warning audit_firewall_setting audit_infrared_remote audit_setup_file audit_screen_lock audit_screen_sharing audit_sleep audit_secure_swap audit_login_guest audit_login_details audit_core_limit audit_remote_apple_events audit_remote_management audit_wake_on_lan audit_file_vault audit_gate_keeper audit_safe_downloads audit_secure_keyboard_entry audit_bonjour_advertising audit_keychain_lock audit_keychain_sync audit_auto_login audit_auto_logout audit_file_extensions audit_internet_sharing audit_java audit_asl audit_auditd audit_wireless audit_app_perms audit_login_root audit_system_preferences audit_system_integrity audit_icloud_drive audit_air_drop audit_air_play audit_asset_cache audit_media_sharing audit_time_machine audit_siri audit_location_services audit_usage_data audit_screen_corner audit_lockdown audit_universal_control audit_touch_id audit_apfs audit_core_storage audit_amfi audit_sudo_timeout audit_sudo_timestamp audit_sudo_authenticate audit_sudo_nopassword audit_sudo_logfile audit_sudo_usepty audit_sudo_perms audit_safari_auto_run audit_safari_history audit_safari_warn audit_safari_tracking audit_safari_auto_fill audit_safari_allow_popups audit_safari_javascript audit_safari_show_statusbar audit_account_switching } ================================================ FILE: modules/full/full_audit_other_daemons.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_other_daemons # # Audit other daemons and startup services #. full_audit_other_daemons () { print_function "full_audit_other_daemons" audit_xinetd audit_other_daemons audit_legacy audit_inetd audit_inetd_logging audit_online_documentation audit_ncs audit_i4ls } ================================================ FILE: modules/full/full_audit_other_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_other_services # # Other remaining services #. full_audit_other_services () { print_function "full_audit_other_services" audit_bluetooth audit_postgresql audit_encryption_kit audit_biosdevname audit_apport audit_pae } ================================================ FILE: modules/full/full_audit_password_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_password_services # # Audit password related services #. full_audit_password_services () { print_function "full_audit_password_services" audit_rsa_securid_pam audit_system_auth audit_system_auth_use_uid audit_password_expiry audit_password_strength audit_passwd_perms audit_retry_limit audit_login_records audit_failed_logins audit_login_delay audit_pass_req audit_pam_wheel audit_pam_authtok audit_password_hashing "${password_hashing}" audit_pam_deny audit_crypt_policy audit_account_lockout audit_sudo_timeout audit_sudo_timestamp audit_sudo_authenticate audit_sudo_nopassword audit_sudo_logfile audit_sudo_usepty audit_sudo_perms } ================================================ FILE: modules/full/full_audit_power_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_power_services #. # Audit power related services #. full_audit_power_services () { print_function "full_audit_power_services" audit_power_management audit_sys_suspend } ================================================ FILE: modules/full/full_audit_print_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_print_services # # Audit print services #. full_audit_print_services () { print_function "full_audit_print_services" audit_ppd_cache audit_print audit_cups audit_printer_sharing } ================================================ FILE: modules/full/full_audit_routing_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_routing_services # # Audit routing services #. full_audit_routing_services () { print_function 'full_audit_routing_services' audit_routing_daemons audit_routing_params } ================================================ FILE: modules/full/full_audit_shell_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_shell_services # # Audit remote shell services #. full_audit_shell_services () { print_function "full_audit_shell_services" audit_issue_banner audit_ssh_config audit_ssh_perms audit_remote_consoles audit_ssh_forwarding audit_remote_shell audit_console_login audit_security_banner audit_xinetd_server audit_telnet_banner audit_telnet_server audit_talk_server audit_talk_client audit_pam_rhosts audit_user_netrc audit_user_rhosts audit_rhosts_files audit_netrc_files audit_serial_login audit_sulogin audit_shell_timeout audit_esxi_shell } ================================================ FILE: modules/full/full_audit_update_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_update_services # # Update services #. full_audit_update_services () { print_function "full_audit_update_services" audit_yum_conf audit_software_update } ================================================ FILE: modules/full/full_audit_user_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_user_services # # Audit users and groups #. full_audit_user_services () { print_function "full_audit_user_services" audit_root_access audit_root_home audit_root_path audit_root_primary_group audit_root_ssh_keys audit_mesgn audit_writesrv audit_groups_exist audit_home_perms audit_home_ownership audit_duplicate_users audit_duplicate_groups audit_user_dotfiles audit_forward_files audit_default_umask audit_password_fields audit_password_lock audit_password_history audit_group_fields audit_reserved_ids audit_super_users audit_daemon_umask audit_cron_perms audit_wheel_group audit_wheel_su audit_old_users audit_cron_allow audit_cron audit_system_accounts audit_shadow_group audit_dcui } ================================================ FILE: modules/full/full_audit_virtualisation_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_virtualisation_services # # Audit vitualisation services #. full_audit_virtualisation_services () { print_function "full_audit_virtualisation_services" audit_zones audit_xen } ================================================ FILE: modules/full/full_audit_web_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_web_services # # Audit web services full_audit_web_services () { print_function "full_audit_web_services" audit_webconsole audit_wbem audit_apache audit_webmin } ================================================ FILE: modules/full/full_audit_windows_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_windows_services # # Audit windows services #. full_audit_windows_services () { print_function "full_audit_windows_services" audit_smbpasswd_perms audit_smbconf_perms audit_samba audit_wins audit_winbind } ================================================ FILE: modules/full/full_audit_x11_services.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # full_audit_x11_services # # Audit X11 Services #. full_audit_x11_services () { print_function "full_audit_x11_services" audit_cde_ttdb audit_cde_cal audit_cde_spc audit_cde_print audit_xlogin audit_gdm_conf audit_cde_banner audit_gnome_banner audit_cde_screen_lock audit_gnome_screen_lock audit_gnome_automount audit_opengl audit_font_server audit_vnc audit_xwindows_server } ================================================ FILE: modules/groups/audit_duplicate_groups.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_duplicate_groups # # Check duplicate groups # # Refer to Section(s) 9.2.15,17 Page(s) 173-5 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.16,19 Page(s) 204-5 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.15,17 Page(s) 176-9 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 10.15,17 Page(s) 164-7 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.2.17 Page(s) 220 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9.16,19 Page(s) 83-4,5-6 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.16,19 Page(s) 129-30,131-2 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.17,19 Page(s) 270,72 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.17,19 Page(s) 284,6 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 7.2.6,8 Page(s) 975-6,979-80 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_duplicate_groups () { print_function "audit_duplicate_groups" string="Duplicate Groups" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "AIX" ]; then audit_duplicate_ids "1" "groups" "name" "/etc/group" audit_duplicate_ids "3" "groups" "id" "/etc/group" else na_message "${string}" fi } ================================================ FILE: modules/groups/audit_group_fields.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_group_fields # # Refer to Section(s) 5.4.2.3 Page(s) 698-9 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_group_fields () { print_function "audit_group_fields" string="Group Fields" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${audit_mode}" != 2 ]; then check_file="/etc/group" group_list=$( awk -F: '($3 == 0) { print $1 }' "${check_file}" | grep -v root ) if [ "${group_list}" = "" ]; then inc_secure "No non root groups have GID 0" else for group_name in ${group_list}; do if [ "$group_name" != "root" ]; then inc_insecure "Non root group ${group_name} has GID 0" fi done fi else check_file="/etc/group" restore_file "${check_file}" "${restore_dir}" fi else na_message "${string}" fi } ================================================ FILE: modules/groups/audit_groups_exist.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2154 # audit_groups_exist # # Check groups # # Refer to Section(s) 9.2.11 Page(s) 170-1 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.11 Page(s) 196-7 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.11 Page(s) 173-4 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.2.15 Page(s) 282 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 13.11 Page(s) 161-2 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 9.11 Page(s) 80 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.11 Page(s) 124-5 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.15 Page(s) 269 CIS Amazon Linux Benchmark v2.1.0 # Refer to Section(s) 6.2.15 Page(s) 282 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 7.2.3 Page(s) 970-1 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_groups_exist () { print_function "audit_groups_exist" string="User Groups" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then check_file="/etc/group" group_fail=0 if [ "${audit_mode}" != 2 ]; then for group_id in $( getent passwd | cut -f4 -d ":" ); do group_exists=$( grep -v "^#" "${check_file}" | cut -f3 -d:| grep -c "^${group_id}$" | sed "s/ //g" ) if [ "$group_exists" = 0 ]; then group_fail=1 if [ "${audit_mode}" = 1 ];then inc_insecure "Group \"${group_id}\" does not exist in group file \"${check_file}\"" fi fi done if [ "${group_fail}" != 1 ]; then if [ "${audit_mode}" = 1 ];then inc_secure "No non existant group issues" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/groups/audit_root_primary_group.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_root_primary_group # # Check root primary group # # Refer to Section(s) 7.3 Page(s) 147 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 7.3 Page(s) 170 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 7.3 Page(s) 150 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.4.3 Page(s) 253 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 10.3 Page(s) 139-140 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 5.4.3 Page(s) 232 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 7.4 Page(s) 104-5 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 5.4.3 Page(s) 245 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_root_primary_group () { print_function "audit_root_primary_group" string="Root Primary Group" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then log_file="root_primary_group.log" check_file="/etc/group" group_check=$( grep "^root:" /etc/passwd | cut -f4 -d: ) if [ "${audit_mode}" != 2 ]; then if [ "${group_check}" != "0" ];then if [ "${audit_mode}" = 1 ]; then inc_insecure "Group \"${group_id}\" does not exist in group file \"${check_file}\"" fix_message "usermod -g 0 root" fi if [ "${audit_mode}" = 0 ];then log_file="${work_dir}/${log_file}" echo "${group_check}" > "${log_file}" set_message "Primary group for root to root" usermod -g 0 root fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Primary group for root is root" fi fi else restore_file="${restore_dir}/${log_file}" if [ -e "${restore_file}" ]; then restore_value=$( cat "${restore_file}" ) if [ "${restore_value}" != "${group_check}" ]; then verbose_message "Restoring: Primary root group to \"${restore_value}\"" "restore" usermod -g "${restore_value}" root fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/gui/audit_font_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_font_server # # Turn off font server #. audit_font_server () { print_function "audit_font_server" string="Font Server" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then for service_name in "svc:/application/x11/xfs:default" \ "svc:/application/font/stfsloader:default" \ "svc:/application/font/fc-cache:default"; do check_sunos_service "${service_name}" "disabled" done fi fi if [ "${os_name}" = "Linux" ]; then service_name="xfs" check_linux_service "${service_name}" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/gui/audit_gdm_conf.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_gdm_conf # # Gnome Display Manager should not be used on a server, but if it is it # should be locked down to disable root access. # # Refer to Section(s) 1.8.10 Page(s) 193-4 CIS Ubuntu 22.04 Benchmaek v1.0.0 # Refer to Section(s) 1.7.1,10 Page(s) 197-8,223-5 CIS Ubuntu 24.04 Benchmaek v1.0.0 #. audit_gdm_conf () { print_function "audit_gdm_conf" string="GDM Configuration" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_file="/etc/X11/gdm/gdm.conf" if [ -e "${check_file}" ]; then check_linux_package "uninstall" "gdm3" check_message "${string}" "check" check_file_value "is" "${check_file}" "AllowRoot" "eq" "false" "hash" check_file_value "is" "${check_file}" "AllowRemoteRoot" "eq" "false" "hash" check_file_value "is" "${check_file}" "Use24Clock" "eq" "true" "hash" check_file_perms "${check_file}" "0644" "root""root" fi check_file="/etc/gdm3/greeter.dconf-defaults" if [ -e "${check_file}" ]; then check_message "GDM3 Greeter User List Configuration" check_file_value "is" "${check_file}" "disable-user-list" "eq" "true" "hash" fi for check_file in /etc/gdm/custom.conf /etc/gdm3/custom.conf /etc/gdm/daemon.conf /etc/gdm3/daemon.conf; do if [ -e "${check_file}" ]; then verbose_message "GDM3 XDMCP Configuration" "check" check_file_value_with_position "is" "${check_file}" "Enable" "eq" "false" "hash" "after" "xdmcp" fi done else na_message "${string}" fi } ================================================ FILE: modules/gui/audit_gnome_automount.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2129 # shellcheck disable=SC2154 # audit_gnome_automount # # Check Gnome Automount # # Refer to Section(s) 1.8.6-9 Page(s) 172-92 CIS Ubuntu 22.04 Benchmaek v1.0.0 # Refer to Section(s) 1.7.7-9 Page(s) 214-22 CIS Ubuntu 24.04 Benchmaek v1.0.0 #. audit_gnome_automount () { print_function "audit_gnome_automount" string="Automount/Autorun for GNOME Users" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_gsettings_value "org.gnome.desktop.media-handling" "automount-open" "false" check_gsettings_value "org.gnome.desktop.media-handling" "automount" "false" check_gsettings_value "org.gnome.desktop.media-handling" "autorun-never" "true" if [ "${os_vendor}" = "Ubuntu" ]; then if [ "${os_version}" -ge 22 ]; then if [ -d "/etc/dconf" ]; then check_file="/etc/dconf/db/ibus.d/00-media-automount" if [ "${ansible_mode}" = 1 ]; then string="Automount GNOME Users" echo "- name: ${string}" echo " copy:" echo " content: |" echo " [org/gnome/desktop/media-handling]" echo " automount-open=false" echo " automount=false" echo " dest: ${check_file}" fi if [ -f "${check_file}" ]; then check_file_value_with_position "is" "${check_file}" "automount-open" "eq" "false" "hash after" "handling" check_file_value_with_position "is" "${check_file}" "automount" "eq" "false" "hash after" "handling" check_file_value_with_position "is" "${check_file}" "autorun-never" "eq" "true" "hash after" "handling" else if [ "${audit_mode}" = 1 ]; then fix_message "echo \"[org/gnome/desktop/media-handling]\" > ${check_file}" fix_message "echo \"automount-open=false\" >> ${check_file}" fix_message "echo \"automount=false\" >> ${check_file}" fix_message "echo \"autorun-never=true\" >> ${check_file}" fix_message "dconf update" "fix" fi if [ "${audit_mode}" = 0 ]; then echo "[org/gnome/desktop/media-handling]" > "${check_file}" echo "automount-open=false" >> "${check_file}" echo "automount=false" >> "${check_file}" echo "autorun-never=true" >> "${check_file}" dconf update fi if [ "${audit_mode}" = 2 ]; then if [ -f "${check_file}" ]; then rm "${check_file}" fi fi fi check_file="/etc/dconf/db/ibus.d/locks/00-media-automount" if [ "${ansible_mode}" = 1 ]; then string="Automount/Autorun Lock GNOME Users" echo "- name: ${string}" echo " copy:" echo " content: |" echo " /org/gnome/desktop/media-handling/automount" echo " /org/gnome/desktop/media-handling/automount-open" echo " /org/gnome/desktop/media-handling/autorun-never" echo " dest: ${check_file}" fi if [ -f "${check_file}" ]; then check_append_file "${check_file}" "/org/gnome/desktop/media-handling/automount-false" "hash" check_append_file "${check_file}" "/org/gnome/desktop/media-handling/automount" "hash" check_append_file "${check_file}" "/org/gnome/desktop/media-handling/autorun-never" "hash" else if [ "${audit_mode}" = 1 ]; then fix_message "mkdir -p /etc/dconf/db/ibus.d/locks" fix_message "echo \"/org/gnome/desktop/media-handling/automount\" > ${check_file}" fix_message "echo \"/org/gnome/desktop/media-handling/automount-open\" >> ${check_file}" fix_message "echo \"/org/gnome/desktop/media-handling/autorun-never\" >> ${check_file}" fix_message "dconf update" "fix" fi if [ "${audit_mode}" = 0 ]; then mkdir -p /etc/dconf/db/ibus.d/locks echo "/org/gnome/desktop/media-handling/automount" > "${check_file}" echo "/org/gnome/desktop/media-handling/automount-open" > "${check_file}" echo "/org/gnome/desktop/media-handling/autorun-never" > "${check_file}" dconf update fi if [ "${audit_mode}" = 2 ]; then if [ -f "${check_file}" ]; then rm "${check_file}" fi fi fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/gui/audit_gnome_banner.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2086 # shellcheck disable=SC2154 # audit_gnome_banner # # Create Warning Banner for GNOME Users # # Refer to Section(s) 8.3 Page(s) 151 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 8.2 Page(s) 174-5 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 8.3 Page(s) 154-5 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 11.3 Page(s) 143-4 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.7.2 Page(s) 84-5 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 8.3 Page(s) 69-70 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 8.3 Page(s) 113-4 CIS Solaris 10 Benchmark v5.1.0 #. audit_gnome_banner () { print_function "audit_gnome_banner" string="Gnome Warning Banner" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file_value "is" "/etc/X11/gdm.conf" "Welcome" "eq" "Authorised users only" "hash" fi if [ "${os_version}" = "11" ]; then check_file="/etc/gdm/Init/Default" if [ "${audit_mode}" != 2 ]; then if [ -f "${check_file}" ]; then gdm_check=$( grep 'Security Message' "${check_file}" | cut -f3 -d= ) if [ "${gdm_check}" != "/etc/issue" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Warning banner not found in \"${check_file}\"" fix_message "echo \" --title=\"Security Message\" --filename=/etc/issue\" >> ${check_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" verbose_message "Setting: Warning banner in \"${check_file}\"" echo " --title=\"Security Message\" --filename=/etc/issue" >> "${check_file}" if [ "${os_version}" = "10" ]; then eval "pkgchk -f -n -p ${check_file} 2> /dev/null" else pkg fix $( pkg search "${check_file}" | grep pkg | awk '{print $4}' ) fi fi fi if [ "${file_entry}" = "" ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "Warning banner in \"${check_file}\"" fi fi else restore_file "${check_file}" "${restore_dir}" fi fi fi fi if [ "${os_name}" = "Linux" ]; then check_file="/etc/dconf/profile/gdm" if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "user-db" "colon" "user" "hash" check_file_value "is" "${check_file}" "system-db" "colon" "gdm" "hash" check_file_value "is" "${check_file}" "file-db" "colon" "/usr/share/gdm/greeter-dconf-defaults" "hash" fi check_file="/etc/dconf/db/gdm.d/01-banner-message" if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "banner-message-enable" "eq" "true" "hash" check_file_value "is" "${check_file}" "banner-message-text" "eq" "Authorized uses only. All activity may be monitored and reported." "hash" fi check_file="/etc/gdm3/greeter.dconf-defaults" if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "banner-message-enable" "eq" "true" "hash" check_file_value "is" "${check_file}" "banner-message-text" "eq" "Authorized uses only. All activity may be monitored and reported." "hash" fi fi gconf_test=$( command -v gconftool 2> /dev/null | wc -l | sed "s/ //g" ) if [ "$gconf_test" = "1" ]; then gconf_bin=$( command -v gconftool 2> /dev/null ) fi if [ "${os_name}" = "Linux" ] && [ "$gconf_test" = "1" ]; then warn_message="Authorised users only" actual_value=$( gconftool-2 --get /apps/gdm/simple-greeter/banner_message_text ) log_file="gnome_banner_warning" if [ "${audit_mode}" != 2 ]; then if [ "${actual_value}" != "${warning_message}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Warning banner not found in \"${check_file}\"" fix_message "gconftool-2 -direct -config-source=xml:readwrite:$HOME/.gconf -t string -s /apps/gdm/simple-greeter/banner_message_text \"${warning_message}\"" fi if [ "${audit_mode}" = 0 ]; then verbose_message "Setting: Warning banner to \"${warning_message}\"" log_file="${work_dir}/${log_file}" echo "${actual_value}" > "${log_file}" gconftool-2 -direct -config-source=xml:readwrite:$HOME/.gconf -t string -s /apps/gdm/simple-greeter/banner_message_text \"${warning_message}\" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Warning banner is set to \"${warning_message}\"" fi fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then restore_value=$( cat "${log_file}" ) if [ "${restore_value}" != "${actual_value}" ]; then verbose_message "Restoring: Warning banner to ${previous_value}" eval "gconftool-2 -direct -config-source=xml:readwrite:$HOME/.gconf -t string -s /apps/gdm/simple-greeter/banner_message_text ${restore_value}" fi fi fi actual_value=$( gconftool-2 --get /apps/gdm/simple-greeter/banner_message_enable ) log_file="gnome_banner_status" if [ "${audit_mode}" != 2 ]; then if [ "${actual_value}" != "true" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Warning banner not found in \"${check_file}\"" fix_message "gconftool-2 -direct -config-source=xml:readwrite:$HOME/.gconf -type bool -set /apps/gdm/simple-greeter/banner_message_enable true" fi if [ "${audit_mode}" = 0 ]; then set_message "Warning banner to \"${warning_message}\"" log_file="${work_dir}/${log_file}" echo "${actual_value}" > "${log_file}" eval "gconftool-2 -direct -config-source=xml:readwrite:$HOME/.gconf -type bool -set /apps/gdm/simple-greeter/banner_message_enable true" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Warning banner is set to \"${warning_message}\"" fi fi else log_file="${restore_dir}/${log_file}" if [ -f "${log_file}" ]; then restore_value=$( cat "${log_file}" ) if [ "${restore_value}" != "${actual_value}" ]; then verbose_message "Restoring: Warning banner to ${previous_value}" eval "gconftool-2 -direct -config-source=xml:readwrite:$HOME/.gconf -type bool -set /apps/gdm/simple-greeter/banner_message_enable ${restore_value}" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/gui/audit_gnome_screen_lock.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2129 # shellcheck disable=SC2154 # audit_gnome_screen_lock # # Check Gnome Screen Lock # # Refer to Section(s) 6.12 Page(s) 55-56 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.8 Page(s) 92-3 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 1.8.4 Page(s) 162-5 CIS Ubuntu 22.04 Benchmaek v1.0.0 # Refer to Section(s) 1.8.5 Page(s) 167-71 CIS Ubuntu 22.04 Benchmaek v1.0.0 #. audit_gnome_screen_lock () { print_function "audit_gnome_screen_lock" string="Screen Lock for GNOME Users" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/usr/openwin/lib/app-defaults/XScreenSaver" "*timeout:" "space" "0:10:00" "bang" check_file_value "is" "/usr/openwin/lib/app-defaults/XScreenSaver" "*lockTimeout:" "space" "0:00:00" "bang" fi if [ "${os_name}" = "Linux" ]; then check_gsettings_value "org.gnome.desktop.session" "idle-delay" "uint32 900" check_gsettings_value "org.gnome.desktop.screensaver" "lock-delay" "uint32 5" if [ "${os_vendor}" = "Ubuntu" ]; then if [ "${os_version}" -ge 22 ]; then if [ -d "/etc/dconf" ]; then check_file="/etc/dconf/db/ibus.d/00-screensaver" if [ -f "${check_file}" ]; then if [ "${ansible_mode}" = 1 ]; then string="Screen Lock for GNOME Users" echo "- name: ${string}" echo " copy:" echo " content: |" echo " [org/gnome/desktop/session]" echo " idle-delay=uint32 900" echo " [org/gnome/desktop/screensaver]" echo " lock-delay=uint32 5" echo " dest: ${check_file}" fi check_file_value_with_position "is" "${check_file}" "idle-delay" "eq" "uint32 900" "hash" "after" "session" check_file_value_with_position "is" "${check_file}" "lock-delay" "eq" "uint32 5" "hash" "after" "screensaver" else if [ "${audit_mode}" = 1 ]; then fix_message "echo \"[org/gnome/desktop/session]\" > ${check_file}" fix_message "echo \"idle-delay=uint32 900\" >> ${check_file}" fix_message "echo \"[org/gnome/desktop/screensaver]\" >> ${check_file}" fix_message "echo \"lock-delay=uint32 5\" >> ${check_file}" fix_message "dconf update" fi if [ "${audit_mode}" = 0 ]; then echo "[org/gnome/desktop/session]" > "${check_file}" echo "idle-delay=uint32 900" >> "${check_file}" echo "[org/gnome/desktop/screensaver]" >> "${check_file}" echo "lock-delay=uint32 5" >> "${check_file}" dconf update fi if [ "${audit_mode}" = 2 ]; then if [ -f "${check_file}" ]; then rm "${check_file}" fi fi fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/gui/audit_kdm_config.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kdm_config # # Turn off kdm config #. audit_kdm_config () { print_function "audit_kdm_config" string="Graphics Configuration" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/platform/i86pc/kdmconfig:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/gui/audit_opengl.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_opengl # # OpenGL. Not required unless running a GUI. Not required on a server. #. audit_opengl () { print_function "audit_opengl" string="OpenGL" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/application/opengl/ogl-select:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/gui/audit_xwindows_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_xwindows_server # # Refer to Section(s) 3.2 Page(s) 59-60 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.3 Page(s) 72-3 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.2 Page(s) 62-3 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.1 Page(s) 52 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.1.20 Page(s) 283-4 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_xwindows_server () { print_function "audit_xwindows_server" string="X Windows Server" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ]; then no_rego=$( yum grouplist 2>&1 | grep "not registered" ) if [ -z "${no_rego}" ]; then check_linux_package_with_group "uninstalled" "X Windows Server" "group" else warn_message "System not registered with a repository" fi else if [ "${os_vendor}" = "Ubuntu" ]; then check_linux_package "uninstall" "xserver-common" fi fi else na_message "${string}" fi } ================================================ FILE: modules/kerberos/audit_kerberos_tgt.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kerberos_tgt # # Check Kerberos Ticket Warning # # Refer to Section(s) 2.6 Page(s) 19 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 2.2.6 Page(s) 26-7 CIS Solaris 10 Benchmark v5.1.0 #. audit_kerberos_tgt () { print_function "audit_kerberos_tgt" string="Kerberos Ticket Warning" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/security/ktkt_warn" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/kerberos/audit_krb5.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_krb5 # # Turn off kerberos if not required #. audit_krb5 () { print_function "audit_krb5" string="Kerberos" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then for service_name in "svc:/network/security/krb5kdc:default" \ "svc:/network/security/kadmin:default" \ "svc:/network/security/krb5_prop:default"; do check_sunos_service "${service_name}" "disabled" done fi fi if [ "${os_name}" = "Linux" ]; then for service_name in kadmin kprop krb524 krb5kdc; do check_linux_service "${service_name}" "off" done fi else na_message "${string}" fi } ================================================ FILE: modules/kernel/audit_kernel_modules.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kernel_modules # # Check Kernel Modules # # Refer to http://kb.vmware.com/kb/2042473. #. audit_kernel_modules () { print_function "audit_kernel_modules" string="Kernel Module Signing" check_message "${string}" if [ "${os_name}" = "VMkernel" ]; then for module in $( esxcli system module list | grep '^[a-z]' | awk '($3 == "true") {print $1}' ); do log_file="kernel_module_${module_name}" backup_file="${work_dir}/${log_file}" current_value=$( esxcli system module get -m "${module_name}" | grep "Signed Status" | awk -F': ' '{print $2}' ) if [ "${audit_mode}" != "2" ]; then if [ "${current_value}" != "VMware Signed" ]; then if [ "${audit_mode}" = "0" ]; then if [ "${syslog_server}" != "" ]; then set_message "Kernel module ${module_name} to disabled" echo "true" > "${backup_file}" esxcli system module set -e false -m "${module_name}" fi fi if [ "${audit_mode}" = "1" ]; then inc_insecure "Kernel module \"${module_name}\" is not signed by VMware" fix_message "esxcli system module set -e false -m ${module_name}" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Kernel module \"${module_name}\" is signed by VMware" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then previous_value=$( cat "${restore_file}" ) if [ "${previous_value}" != "${current_value}" ]; then restore_message "Kernel module to \"${previous_value}\"" "restore" esxcli system module set -e "${previous_value}" -m "${module_name}" fi fi fi done else na_message "${string}" fi } ================================================ FILE: modules/kernel/audit_kernel_params.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kernel_params # # Check Kernel Parameters # # Refer to Section(s) 4.2,5.3 Page(s) 16-19 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.6.1-21 Page(s) 103-131 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 1.6.1-21 Page(s) CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 3.1.1-18 Page(s) 38-61 CIS Solaris 10 Benchmark v5.1.0 #. audit_kernel_params () { print_function "audit_kernel_params" string="Kernel Parameters" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_no "ipsrcrouteforward" "0" check_no "ipignoreredirects" "1" check_no "clean_partial_conns" "1" check_no "ipsrcroutesend" "0" check_no "ipforwarding" "0" check_no "ipsendredirects" "0" check_no "ip6srcrouteforward" "0" check_no "directed_broadcast" "0" check_no "tcp_pmtu_discover" "0" check_no "bcastping" "0" check_no "icmpaddressmask" "0" check_no "udp_pmtu_discover" "0" check_no "ipsrcrouterecv" "0" check_no "nonlocsrcroute" "0" check_no "tcp_tcpsecure" "7" check_no "sockthresh" "60" check_no "rfc1323" "1" check_no "tcp_sendspace" "262144" check_no "tcp_recvspace" "262144" check_no "tcp_mssdflt" "1448" check_no "portcheck" "1" check_no "nfs_use_reserved_ports" "1" fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/sysctl.conf" "kern.securelevel" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "net.inet.tcp.log_in_vain" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "net.inet.udp.log_in_vain" "eq" "1" "hash" if [ "${os_version}" -gt 5 ]; then check_file_value "is" "/etc/sysctl.conf" "security.bsd.see_other_uids" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "security.bsd.see_other_gids" "0" "hash" fi fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" != "11" ]; then create_nddscript check_file="/etc/init.d/ndd-netconfig" audit_ndd_value "/dev/ip" "ip_forward_src_routed" "0" audit_ndd_value "/dev/ip" "ip_forwarding" "0" if [ "${os_version}" -gt 7 ]; then audit_ndd_value "/dev/ip" "ip6_forward_src_routed" "0" audit_ndd_value "/dev/tcp" "tcp_rev_src_routes" "0" audit_ndd_value "/dev/ip" "ip6_forwarding" "0" fi audit_ndd_value "/dev/ip" "ip_forward_directed_broadcasts" "0" audit_ndd_value "/dev/tcp" "tcp_conn_req_max_q0" "4096" audit_ndd_value "/dev/tcp" "tcp_conn_req_max_q" "1024" audit_ndd_value "/dev/ip" "ip_respond_to_timestamp" "0" audit_ndd_value "/dev/ip" "ip_respond_to_timestamp_broadcast" "0" audit_ndd_value "/dev/ip" "ip_respond_to_address_mask_broadcast" "0" audit_ndd_value "/dev/ip" "ip_respond_to_echo_multicast" "0" if [ "${os_version}" -gt 7 ]; then audit_ndd_value "/dev/ip" "ip6_respond_to_echo_multicast" "0" fi audit_ndd_value "/dev/ip" "ip_respond_to_echo_broadcast" "0" audit_ndd_value "/dev/arp" "arp_cleanup_interval" "60000" audit_ndd_value "/dev/ip" "ip_ire_arp_interval" "60000" audit_ndd_value "/dev/ip" "ip_ignore_redirect" "1" if [ "${os_version}" -gt 7 ]; then audit_ndd_value "/dev/ip" "ip6_ignore_redirect" "1" fi audit_ndd_value "/dev/tcp" "tcp_extra_priv_ports_add" "6112" audit_ndd_value "/dev/ip" "ip_strict_dst_multihoming" "1" if [ "${os_version}" -gt 7 ]; then audit_ndd_value "/dev/ip" "ip6_strict_dst_multihoming" "1" fi audit_ndd_value "/dev/ip" "ip_send_redirects" "0" if [ "${os_version}" -gt 7 ]; then audit_ndd_value "/dev/ip" "ip6_send_redirects" "0" fi fi if [ "${audit_mode}" = 2 ]; then if [ "${os_name}" = "AIX" ]; then for parameter_name in ipsrcrouteforward ipignoreredirects \ clean_partial_conns ipsrcroutesend ipforwarding ipsendredirects \ ip6srcrouteforward directed_broadcast tcp_pmtu_discover bcastping \ icmpaddressmask udp_pmtu_discover ipsrcrouterecv nonlocsrcroute \ tcp_tcpsecure sockthresh rfc1323 tcp_sendspace tcp_recvspace \ tcp_mssdflt portcheck nfs_use_reserved_ports; do check_no "${parameter_name}" done else if [ -f "${check_file}" ]; then check_file_exists "${check_file}" "no" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/kubernetes/audit_kubernetes_apiserver.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2009 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kubernetes_apiserver # # Check Kubernetes API server # # Refer to Section(s) 1.1.1-39 Page(s) 13-88 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.4.1-21 Page(s) 109-128 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.5.1-7 Page(s) 151-164 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.6.1-8 Page(s) 165-180 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.7.1-7 Page(s) 181-194 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.1.1-14 Page(s) 195-222 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.2.1-10 Page(s) 223-242 CIS Kubernetes Benchmark v1.4.0 # # Still to be completed #. audit_kubernetes_apiserver () { print_function "audit_kubernetes_apiserver" string="Kubernetes API Server" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then daemon_check=$( ps -ef | grep "kube-apiserver" |grep -v grep ) if [ "${daemon_check}" ]; then check_file="/etc/kubernetes/manifests/kube-apiserver.yaml" if [ -f "${check_file}" ]; then disable_value "${check_file}" "--basic-auth-file" "hash" disable_value "${check_file}" "--insecure-allow-any-token" "hash" disable_value "${check_file}" "--insecure-bind-address" "hash" disable_value "${check_file}" "--token-auth-file" "hash" check_file_perms "${check_file}" "0644" "root" "root" check_file_value "is" "${check_file}" "--anonymous-auth" "eq" "false" "hash" check_file_value "is" "${check_file}" "--kubelet-https" "eq" "true" "hash" check_file_value "is" "${check_file}" "--insecure-port" "eq" "0" "hash" check_file_value "is" "${check_file}" "--profiling" "eq" "false" "hash" check_file_value "is" "${check_file}" "--repair-malformed-updates" "eq" "false" "hash" check_file_value "is" "${check_file}" "--audit-log-maxage" "eq" "30" "hash" check_file_value "is" "${check_file}" "--audit-log-maxbackup" "eq" "10" "hash" check_file_value "is" "${check_file}" "--audit-log-maxsize" "eq" "100" "hash" check_file_value "set" "${check_file}" "--enable-admission-plugins" "eq" "na" "hash" check_file_value "set" "${check_file}" "--kubelet-client-certificate" "eq" "na" "hash" check_file_value "set" "${check_file}" "--kubelet-client-key" "eq" "na" "hash" check_file_value "is" "${check_file}" "--service-account-lookup" "eq" "true" "hash" check_file_value "set" "${check_file}" "--service-account-key-file" "eq" "na" "hash" check_file_value "set" "${check_file}" "--etcd-certfile" "eq" "na" "hash" check_file_value "set" "${check_file}" "--etcd-keyfile" "eq" "na" "hash" check_file_value "set" "${check_file}" "--tls-cert-file" "eq" "na" "hash" check_file_value "set" "${check_file}" "--tls-private-key-file" "eq" "na" "hash" check_file_value "set" "${check_file}" "--client-ca-file" "eq" "na" "hash" check_file_value "set" "${check_file}" "--etcd-cafile" "eq" "na" "hash" check_file_value "is" "${check_file}" "--authorization-mode" "eq" "Node,RBAC" "hash" check_file_value "set" "${check_file}" "--admission-control-config-file" "eq" "na" "hash" check_file_value "set" "${check_file}" "--experimental-encryption-provider-config" "eq" "na" "hash" check_file_value "not" "${check_file}" "--enable-admission-plugins" "eq" "AlwaysAdmit" "hash" # no check_file_value "is" "${check_file}" "--enable-admission-plugins" "eq" "AlwaysPullImages" "hash" # yes check_file_value "is" "${check_file}" "--enable-admission-plugins" "eq" "DenyEscalatingExec" "hash" # yes check_file_value "is" "${check_file}" "--enable-admission-plugins" "eq" "SecurityContextDeny" "hash" # yes check_file_value "is" "${check_file}" "--enable-admission-plugins" "eq" "NamespaceLifecycle" "hash" # no check_file_value "is" "${check_file}" "--enable-admission-plugins" "eq" "PodSecurityPolicy" "hash" # yes check_file_value "not" "${check_file}" "--enable-admission-plugins" "eq" "ServiceAccount" "hash" # no check_file_value "is" "${check_file}" "--enable-admission-plugins" "eq" "NodeRestriction" "hash" # yes check_file_value "is" "${check_file}" "--enable-admission-plugins" "eq" "EventRateLimit" "hash" # yes check_file_value "not" "${check_file}" "--feature-gates" "eq" "AdvancedAuditing=false" "hash" # no check_file_value "is" "${check_file}" "--audit-log-path" "eq" "/var/log/apiserver/audit.log" "hash" check_file_value "is" "${check_file}" "--tls-cipher-suites" "eq" "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AE S_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM _SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM _SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256" "hash" fi if [ -f "${check_file}" ]; then check_file_value "is" "/etc/kubernetes/apiserver" "KUBE_API_ARGS" "eq" "--feature-gates=AllAlpha=true" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/kubernetes/audit_kubernetes_controller.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2009 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kubernetes_controller # # Check Kubernetes controller # # Refer to Section(s) 1.1.1-39 Page(s) 13-88 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.4.1-21 Page(s) 109-128 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.5.1-7 Page(s) 151-164 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.6.1-8 Page(s) 165-180 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.7.1-7 Page(s) 181-194 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.1.1-14 Page(s) 195-222 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.2.1-10 Page(s) 223-242 CIS Kubernetes Benchmark v1.4.0 # # Still to be completed #. audit_kubernetes_controller () { print_function "audit_kubernetes_controller" string="Kubernetes Controller" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then daemon_check=$( ps -ef | grep "kube-controller-manager" | grep -v grep ) if [ "${daemon_check}" ]; then check_file="/etc/kubernetes/manifests/kube-controller-manager.yaml" if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "--terminated-pod-gc-threshold" "eq" "10" "hash" check_file_value "is" "${check_file}" "--use-service-account-credentials" "eq" "true" "hash" check_file_value "set" "${check_file}" "--service-account-private-key-file" "eq" "na" "hash" check_file_value "set" "${check_file}" "--root-ca-file" "eq" "na" "hash" check_file_value "is" "${check_file}" "--feature-gates" "eq" "RotateKubeletServerCertificate=true" "hash" # yes fi fi else na_message "${string}" fi } ================================================ FILE: modules/kubernetes/audit_kubernetes_etcd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2009 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kubernetes_etcd # # Check Kubernetes etcd # # Refer to Section(s) 1.1.1-39 Page(s) 13-88 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.4.1-21 Page(s) 109-128 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.5.1-7 Page(s) 151-164 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.6.1-8 Page(s) 165-180 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.7.1-7 Page(s) 181-194 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.1.1-14 Page(s) 195-222 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.2.1-10 Page(s) 223-242 CIS Kubernetes Benchmark v1.4.0 # # Still to be completed #. audit_kubernetes_etcd () { print_function "audit_kubernetes_etcd" string="Kubernetes etcd" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then daemon_check=$( ps -ef | grep "etcd" |grep -v grep ) if [ "${daemon_check}" ]; then check_file="/etc/kubernetes/manifests/etcd.yaml" if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0644" "root" "root" check_file_value "is" "${check_file}" "--client-cert-auth" "eq" "true" "hash" check_file_value "set" "${check_file}" "--cert-file" "eq" "na" "hash" check_file_value "set" "${check_file}" "--key-file" "eq" "na" "hash" check_file_value "is" "${check_file}" "--peer-client-cert-auth" "eq" "true" "hash" check_file_value "is" "${check_file}" "--peer-auto-tls" "eq" "false" "hash" check_file_value "set" "${check_file}" "--trusted-ca-file" "eq" "na" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/kubernetes/audit_kubernetes_kubelet.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2009 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kubernetes_kubelet # # Check Kubernetes kubelet # # Refer to Section(s) 1.1.1-39 Page(s) 13-88 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.4.1-21 Page(s) 109-128 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.5.1-7 Page(s) 151-164 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.6.1-8 Page(s) 165-180 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.7.1-7 Page(s) 181-194 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.1.1-14 Page(s) 195-222 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.2.1-10 Page(s) 223-242 CIS Kubernetes Benchmark v1.4.0 # # Still to be completed #. audit_kubernetes_kubelet () { print_function "audit_kubernetes_kubelet" string="Kubernetes kubelet" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then daemon_check=$( ps -ef | grep "kubelet" | grep -v grep ) if [ "${daemon_check}" ]; then check_file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0755" "root" "root" check_file_value "is" "${check_file}" "KUBELET_SYSTEM_PODS_ARGS" "eq" "--anonymous-auth=false" "hash" check_file_value "is" "${check_file}" "KUBELET_AUTHZ_ARGS" "eq" "--authorization-mode=Webhook" "hash" check_file_value "is" "${check_file}" "KUBELET_AUTHZ_ARGS" "eq" "--client-ca-file=[A-Z,a-z]" "hash" check_file_value "is" "${check_file}" "KUBELET_SYSTEM_PODS_ARGS" "eq" "--read-only-port=0" "hash" check_file_value "is" "${check_file}" "KUBELET_SYSTEM_PODS_ARGS" "eq" "--streaming-connection-idle-timeout=5m" "hash" check_file_value "is" "${check_file}" "KUBELET_SYSTEM_PODS_ARGS" "eq" "--protect-kernel-defaults=true" "hash" check_file_value "not" "${check_file}" "KUBELET_SYSTEM_PODS_ARGS" "eq" "--make-iptables-util-chains" "hash" check_file_value "not" "${check_file}" "KUBELET_SYSTEM_PODS_ARGS" "eq" "--hostname-override" "hash" check_file_value "is" "${check_file}" "KUBELET_SYSTEM_PODS_ARGS" "eq" "--event-qps=0" "hash" check_file_value "is" "${check_file}" "KUBELET_CERTIFICATE_ARGS" "eq" "--tls-cert-file=[A-Z,a-z]" "hash" check_file_value "is" "${check_file}" "KUBELET_CERTIFICATE_ARGS" "eq" "--tls-private-key-file=[A-Z,a-z]" "hash" check_file_value "is" "${check_file}" "KUBELET_CADVISOR_ARGS" "eq" "--cadvisor-port=0" "hash" check_file_value "is" "${check_file}" "KUBELET_CERTIFICATE_ARGS" "eq" "--rotate-certificates=true" "hash" check_file_value "is" "${check_file}" "KUBELET_CERTIFICATE_ARGS" "eq" "--feature-gates=RotateKubeletServerCertificate=true" "hash" check_file_value "is" "${check_file}" "--tls-cipher-suites" "eq" "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AE S_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM _SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM _SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/kubernetes/audit_kubernetes_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2009 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kubernetes_perms # # Check Kubernetes permissions # # Refer to Section(s) 1.1.1-39 Page(s) 13-88 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.4.1-21 Page(s) 109-128 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.5.1-7 Page(s) 151-164 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.6.1-8 Page(s) 165-180 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.7.1-7 Page(s) 181-194 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.1.1-14 Page(s) 195-222 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.2.1-10 Page(s) 223-242 CIS Kubernetes Benchmark v1.4.0 # # Still to be completed #. audit_kubernetes_perms () { print_function "audit_kubernetes_perms" string="Kubernetes permissions" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then check_file="/var/lib/etcd" if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0700" "etcd" "etcd" fi for check_file in /etc/kubernetes/admin.conf /etc/kubernetes/scheduler.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/kubelet.conf; do if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0644" "root" "root" fi done check_dir="/etc/kubernetes/pki" if [ -d "${check_dir}" ]; then file_list=$( find "${check_dir}" -name "*.crt" -type f -maxdepth 1 ) for check_file in ${file_list}; do check_file_perms "${check_file}" "0644" "root" "root" done file_list=$( find "${check_dir}" -name "*.key" -type f -maxdepth 1 ) for check_file in ${file_list}; do check_file_perms "${check_file}" "0600" "root" "root" done fi else na_message "${string}" fi } ================================================ FILE: modules/kubernetes/audit_kubernetes_scheduler.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2009 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_kubernetes_scheduler # # Check Kubernetes scheduler # # Refer to Section(s) 1.1.1-39 Page(s) 13-88 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.4.1-21 Page(s) 109-128 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.5.1-7 Page(s) 151-164 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.6.1-8 Page(s) 165-180 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 1.7.1-7 Page(s) 181-194 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.1.1-14 Page(s) 195-222 CIS Kubernetes Benchmark v1.4.0 # Refer to Section(s) 2.2.1-10 Page(s) 223-242 CIS Kubernetes Benchmark v1.4.0 # # Still to be completed #. audit_kubernetes_scheduler () { print_function "audit_kubernetes_scheduler" string="Kubernetes scheduler" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then daemon_check=$( ps -ef | grep "kube-scheduler" | grep -v grep ) if [ "${daemon_check}" ]; then check_file="/etc/kubernetes/manifests/kube-scheduler.yaml" if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0644" "root" "root" check_file_value "is" "${check_file}" "--audit-policy-file" "eq" "/etc/kubernetes/audit-policy.yaml" "hash" check_file_value "is" "${check_file}" "--request-timeout" "eq" "300s" "hash" check_file_value "is" "${check_file}" "--address" "eq" "127.0.0.1" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/ldap/audit_ldap.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ldap # # Turn off ldap # # Refer to Section(s) 2.3.5 Page(s) 115 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.3.5 Page(s) 128 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 2.3.3 Page(s) 121 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.2.5 Page(s) 300-1 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_ldap () { print_function "audit_ldap" string="LDAP Client" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/ldap/client:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_package "uninstall" "openldap-clients" check_linux_package "uninstall" "ldap-utils" fi else na_message "${string}" fi } ================================================ FILE: modules/ldap/audit_ldap_cache.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ldap_cache # # Check LDAP cache # # Refer to Section(s) 2.2.5 Page(s) 25-6 CIS Solaris 10 Benchmark v5.1.0 #. audit_ldap_cache () { print_function "audit_ldap_cache" string="LDAP Cache" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/network/ldap/client" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "ldap" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/ldap/audit_ldap_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ldap_server # # Check LDAP server # # Refer to Section(s) 3.7 Page(s) 63-4 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.7 Page(s) 76 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.7 Page(s) 66-7 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.6 Page(s) 106 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.6 Page(s) 56-7 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.2.6 Page(s) 98 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.6 Page(s) 106 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.7 Page(s) 245-6 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_ldap_server () { print_function "audit_ldap_server" string="LDAP Server" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_linux_service "slapd" "off" check_linux_package "uninstall" "slapd" else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_aide.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_aide # # Check AIDE # # Refer to Section(s) 1.3.1-2 Page(s) 73-7 CIS Ubuntu LTS 16.04 Benchmark v2.0.0 # Refer to Section(s) 1.3.1-2 Page(s) 73-7 CIS Ubuntu LTS 18.04 Benchmark v2.1.0 # Refer to Section(s) 1.3.1-2 Page(s) 74-8 CIS Ubuntu LTS 20.04 Benchmark v1.0.0 # Refer to Section(s) 1.3.1-2,4.1.4.11 Page(s) 104-8,551-2 CIS Ubuntu LTS 22.04 Benchmark v1.0.0 # Refer to Section(s) 6.3.1-3 Page(s) 924-31 CIS Ubuntu LTS 24.04 Benchmark v1.0.0 #. audit_aide () { print_function "audit_aide" string="AIDE" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_linux_package "install" "aide" check_linux_package "install" "aide-common" if [ -d "/etc/aide" ]; then check_file_value "is" "/etc/aide/aide.conf" "/sbin/auditctl" "space" "p+i+n+u+g+s+b+acl+xattrs+sha512" "hash" check_file_value "is" "/etc/aide/aide.conf" "/sbin/auditd" "space" "p+i+n+u+g+s+b+acl+xattrs+sha512" "hash" check_file_value "is" "/etc/aide/aide.conf" "/sbin/ausearch" "space" "p+i+n+u+g+s+b+acl+xattrs+sha512" "hash" check_file_value "is" "/etc/aide/aide.conf" "/sbin/aureport" "space" "p+i+n+u+g+s+b+acl+xattrs+sha512" "hash" check_file_value "is" "/etc/aide/aide.conf" "/sbin/autrace" "space" "p+i+n+u+g+s+b+acl+xattrs+sha512" "hash" check_file_value "is" "/etc/aide/aide.conf" "/sbin/augenrules" "space" "p+i+n+u+g+s+b+acl+xattrs+sha512" "hash" fi if [ "${os_vendor}" = "Ubuntu" ]; then if [ "${os_version}" -lt 24 ]; then check_append_file "/etc/cron.d/aide" "0 5 * * * /usr/bin/aide.wrapper --config /etc/aide/aide.conf --check" "hash" else check_linux_service "dailyaidecheck.timer" "on" fi else check_append_file "/etc/cron.d/aide" "0 5 * * * /usr/bin/aide.wrapper --config /etc/aide/aide.conf --check" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_apparmor.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_apparmor # # Check AppArmor # # Refer to Section(s) 4.5 Page(s) 38-9 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.6.2.1,1.6.3 Page(s) 69-70,73-4 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.3.1.1-2 Page(s) 151-4 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_apparmor () { print_function "audit_apparmor" string="AppArmor Unconfined Applications" check_message "${string}" if [ "${os_name}" = "Linux" ]; then do_grub_test=0 do_app_test=1 package_name="apparmor" app_name="AppArmor" if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${os_vendor}" = "SuSE" ]; then check_list="/boot/grub/menu.lst" do_test=1 fi if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 16 ]; then check_list="/boot/grub/grub.cfg /etc/default/grub" do_grub_test=1 do_app_test=1 fi if [ "${do_app_test}" = 1 ]; then get_command="apparmor_status |grep \"unconfined mode\" |awk '{print \$1}'" set_command="sudo aa-enforce /etc/apparmor.d/*" command_message "${get_command}" profile_test=$( eval "${get_command}" ) if [ "${profile_test}" = "0" ]; then inc_secure "There are no unconfined applications" else inc_insecure "There are unconfined applications" fi if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="apparmor_check_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} != 0" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${set_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" else lock_command="${set_command}" lock_message="Confine AppArmor Applications" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi for check_file in ${check_list}; do if [ "${do_grub_test}" = 1 ]; then ansible_counter=$((ansible_counter+1)) string="Package \"${app_name}\"" ansible_value="apparmor_check_${ansible_counter}" check_message "${string}" check_linux_package "install" "${package_name}" if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else if [ -f "${check_file}" ]; then disabled_get_command="grep '${package_name}=0' ${check_file} | head -1 | wc -l | sed 's/ //g'" package_disabled_test=$( grep "${package_name}=0" "${check_file}" | head -1 | wc -l | sed "s/ //g" ) package_enabled_test=$( grep "${package_name}=1" "${check_file}" | head -1 | wc -l | sed "s/ //g" ) else package_disabled_test=0 package_enabled_test=0 fi if [ "${package_disabled_test}" = "1" ]; then inc_insecure "Application \"${app_name}\" is disabled in \"${check_file}\"" temp_file="${temp_dir}/${package_name}" backup_file "${check_file}" lock_command="cat ${check_file} |sed 's/${package_name}=0//g' > ${temp_file} ; cat ${temp_file} > ${check_file} ; aa-enforce /etc/${package_name}.d/*" lock_message="Disabled Application/Package \"${app_name}\" in \"${check_file}\" to removed" if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="apparmor_check_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"${disabled_get_command}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} != 0" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"${lock_command}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi fi if [ "${package_enabled_test}" = "1" ]; then inc_secure "Application \"${app_name}\" is enabled in \"${check_file}\"" else inc_insecure "Application \"${app_name}\" is not enabled in \"${check_file}\"" temp_file="${temp_dir}/${package_name}" backup_file "${check_file}" if [ "${check_file}" = "/etc/default/grub" ]; then command="grep -c \"^GRUB_CMDLINE_LINUX\" \"${check_file}\"" command_message "${command}" line_check=$( eval "${command}" ) if [ -n "${line_check}" ]; then command="grep \"^GRUB_CMDLINE_LINUX\" < \"${check_file}\" |cut -f2 -d= |sed \"s/\"//g\"" command_message "${command}" existing_value=$( eval "${command}" ) new_value="GRUB_CMDLINE_LINUX=\"apparmor=1 security=apparmor ${existing_value}\"" lock_command="cat ${check_file} |sed 's/^GRUB_CMDLINE_LINUX/GRUB_CMDLINE_LINUX=\"${new_value}\"/g' > ${temp_file} ; cat ${temp_file} > ${check_file}" lock_message="Disabled Application/Package \"${app_name}\" removed" run_lockdown "${lock_command}" "${lock_message}" "sudo" else lock_command="echo 'GRUB_CMDLINE_LINUX=\"apparmor=1 security=apparmor\"' >> ${check_file}" lock_message="Enabled ${app_name}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${check_file}" = "/boot/grub/grub.cfg" ]; then lock_command="cat ${check_file} |sed 's/^\s*linux.*/& apparmor=1 security=apparmor/g' > ${temp_file} ; cat ${temp_file} > ${check_file} ; aa-enforce /etc/${package_name}.d/*" lock_message="Application/Package \"${app_name}\" in \"${check_file}\" to enabled" run_lockdown "${lock_command}" "${lock_message}" "sudo" else lock_command="cat ${check_file} |sed 's/^\s*kernel.*/& apparmor=1 security=apparmor/g' > ${temp_file} ; cat ${temp_file} > ${check_file} ; enforce /etc/${package_name}.d/*" lock_message="Application/Package \"${app_name}\" in \"${check_file}\" to enabled" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi fi fi done else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_apport.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_apport # # Check Automatic Error Reporting # # Refer to Section(s) 1.5.3 Page(s) 124 CIS Ubuntu 22.04 Benchmark v1.0.0 # Refer to Section(s) 1.5.5 Page(s) 181-2 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_apport () { print_function "audit_apport" string="Automatic Error Reporting" check_message "${string}" if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 22 ]; then check_file_value "is" "/etc/default/apport" "enabled" "eq" "0" "hash" check_linux_service "apport" "off" else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_avahi_conf.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_avahi_conf # # Check Avahi Configuration # # Refer to Section(s) 3.1.3-6 Page(s) 68-72 CIS RHEL 5 Benchmark v2.1.0 #. audit_avahi_conf () { print_function "audit_avahi_conf" string="Multicast DNS Server" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for check_file in /etc/avahi/avahi-daemon.conf /usr/local/etc/avahi/avahi-daemon.conf; do if [ -f "${check_file}" ]; then check_file_value_with_position "is" "${check_file}" "disable-user-service-publishing" "eq" "yes" "hash" "after" "\[publish\]" check_file_value_with_position "is" "${check_file}" "disable-publishing" "eq" "yes" "hash" "after" "\[publish\]" check_file_value_with_position "is" "${check_file}" "publish-address" "eq" "no" "hash" "after" "\[publish\]" check_file_value_with_position "is" "${check_file}" "publish-binfo" "eq" "no" "hash" "after" "\[publish\]" check_file_value_with_position "is" "${check_file}" "publish-workstation" "eq" "no" "hash" "after" "\[publish\]" check_file_value_with_position "is" "${check_file}" "publish-domain" "eq" "no" "hash" "after" "\[publish\]" check_file_value_with_position "is" "${check_file}" "disallow-other-stacks" "eq" "yes" "hash" "after" "\[server\]" check_file_value_with_position "is" "${check_file}" "check-response-ttl" "eq" "yes" "hash" "after" "\[server\]" fi done else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_avahi_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_avahi_server # # Check Avahi Server # # Refer to Section(s) 3.3 Page(s) 60 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.3 Page(s) 67 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.3 Page(s) 63 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.3 Page(s) 103 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.2 Page(s) 52-3 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.2.3 Page(s) 95 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.3 Page(s) 103 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.2 Page(s) 231-3 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_avahi_server () { print_function "audit_avahi_server" string="Avahi Server" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for service_name in avahi avahi-autoipd avahi-daemon avahi-dnsconfd; do check_linux_service "${service_name}" "off" done else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_biosdevname.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_biosdevname # # Check BIOS dev names # # Refer to Section(s) 6.17 Page(s) 64 SLES 11 Benchmark v1.0.0 #. audit_biosdevname () { print_function "audit_biosdevname" string="BIOS Devname" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "SuSE" ]; then check_linux_package "uninstall" "biosdevname" fi else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_execshield.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_execshield # # Execshield is made up of a number of kernel features to provide protection # against buffer overflow attacks. These features include prevention of # execution in memory data space, and special handling of text buffers. # # Enabling any feature that can protect against buffer overflow attacks # enhances the security of the system. # # Refer to Section(s) 1.6.2 Page(s) 45-46 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.6.2,4 Page(s) 51,52-3 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.6.2 Page(s) 48 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 4.2 Page(s) 36-7 CIS SLES 11 Benchmark v1.0.0 #. audit_execshield () { print_function "audit_execshield" string="XD/NS Support" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ]; then if [ "${os_version}" -gt 4 ]; then check_linux_package "install" "kernel-PAE" check_file_value "is" "/etc/sysctl.conf" "kernel.exec-shield" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "fs.suid.dumpable" "eq" "0" "hash" fi else if [ "${os_vendor}" = "SuSE" ]; then check_linux_package "install" "kernel-pae" fi fi else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_linux_logfiles.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_linux_logfiles # # Check permission on log files under Linux. Make sure they are only readable # by system accounts. #. audit_linux_logfiles () { print_function "audit_linux_logfiles" string="Log File Permissions" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for log_file in boot.log btml cron dmesg ksyms httpd lastlog maillog \ mailman messages news pgsql rpm pkgs sa samba scrollkeeper.log \ secure spooler squid vbox wtmp; do if [ -f "/var/log/${log_file}" ]; then check_file_perms "/var/log/${log_file}" "0600" "root" "root" fi done else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_modprobe_conf.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_modprobe_conf # # Check modprobe on filesystems # # Refer to Section(s) 1.18-24,5.6.1-4 Page(s) 26-30,114-6 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.18-24,4.6.1-4 Page(s) 27-32,90-2 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.1.1.1-8,3.5.1-4 Page(s) 17-25,149-152 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 1.1.1.1-8,3.5.1-4 Page(s) 16-24,144-7 CIS Ubuntu LTS 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.1.1.1-10,3.2.1-4 Page(s) 23-73,365-84 CIS Ubuntu LTS 24.04 Benchmark v1.0.0 # Refer to Section(s) 2.18-24,7.5.1-4 Page(s) 26-30,80-3 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.1.18-24,4.6.1-2 Page(s) 28-33,98-100 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.1.1.1-18,3.5.1-4 Page(s) 16-24,135-8 CIS Amazon Linux Benchmark v2.0.0 #. audit_modprobe_conf () { print_function "audit_modprobe_conf" string="Modprobe Configuration" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for module in cramfs freevxfs hfs hfsplus jffs2 overlayfs squashfs udf usb-storage afs ceph \ cifs ext fat fscache fuse gfs2 nfs_common nfsd smbfs_common tipc rds sctp dccp vfat; do check_append_file "/etc/modprobe.conf" "install ${module} /bin/false" "hash" done else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_pae.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_pae # # Check PAE settings # # Refer to Section(s) 1.5.1 Page(s) 88-9 CIS Ubuntu 22.04 Benchmark v1.0.0 #. audit_pae () { print_function "audit_pae" string="XD/NX Support" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_platform}" = "x86_64" ]; then if [ -f "/var/log/dmesg" ]; then check_nx=$( grep NX < /var/log/dmesg | grep "protection: active" | tail -1 | grep -c active | sed "s/ //g" ) if [ "${check_nx}" = "1" ]; then inc_secure "XD/NX is enabled" else inc_insecure "XD/NX is not enabled" fi else na_message "XD/NX Support is not available on ${os_platform}" fi fi else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_prelink.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_prelink # # Check prelinking # # Refer to Section(s) 1.3.1-2 Page(s) 34-5 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.3.1-2 Page(s) 39-40 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.3.1-2 Page(s) 36-7 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.3.1-2,1.5.4 Page(s) 54-6,66 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 1.3.1-2 Page(s) 49-52 CIS Ubuntu LTS 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.5.2 Page(s) 122-3 CIS Ubuntu LTS 22.04 Benchmark v1.0.0 # Refer to Section(s) 1.5.4 Page(s) 179-80 CIS Ubuntu LTS 24.04 Benchmark v1.0.0 # Refer to Section(s) 8.3.1-2 Page(s) 112-3 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.3.1-2 Page(s) 47-9 CIS Amazon Linux Benchmark v2.0.0 #. audit_prelink () { print_function "audit_prelink" string="Prelinking" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "Amazon" ]; then check_file="/etc/sysconfig/prelink" else check_file="/etc/default/prelink" fi if [ -f "${check_file}" ]; then prelink_check=$( grep PRELINKING "${check_file}" | cut -f2 -d= | sed 's/ //g' ) else prelink_check="no" fi if [ "${prelink_check}" = "yes" ]; then run_lockdown "prelink -ua" "Prelink to disabled" fi check_linux_package "uninstall" "prelink" else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_ptrace_scope.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ptrace_scope # # Refer to Section(s) 1.5.2 Page(s) 170-4 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_ptrace_scope () { print_function "audit_ptrace_scope" string="Ptrace scope is restricted" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "Ubuntu" ]; then if [ "${os_version}" -ge 24 ]; then check_file_value "is" "/etc/sysctl.conf" "kernel.yama.ptrace_scope" "eq" "1" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_selinux.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_selinux # # Make sure SELinux is configured appropriately. # # Refer to Section(s) 1.4.1-5,1.5.1-2 Page(s) 36-40,41-2 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.4.1-5,1.5.1-2 Page(s) 41-45,46-7 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.4.1-5,1.5.1-2 Page(s) 39-42,43-4 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.6.1.1-5 Page(s) 69-74 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 1.6.1.1-3 Page(s) 64-7 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.6.1.1-5 Page(s) 60-66 CIS Amazon Linux Benchmark v2.0.0 #. audit_selinux () { print_function "audit_selinux" string="SELinux" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_file_value "is" "/etc/selinux/config" "SELINUX" "eq" "enforcing" "hash" check_file_value "is" "/etc/selinux/config" "SELINUXTYPE" "eq" "targeted" "hash" check_file_perms "/etc/selinux/config" "0400" "root" "root" for check_file in /etc/grub.conf /boot/grub/grub.cfg; do if [ -e "${check_file}" ]; then check_file_perms "${check_file}" "0400" "root" "root" check_file_value "is" "${check_file}" "selinux" "eq" "1" "hash" check_file_value "is" "${check_file}" "enforcing" "eq" "1" "hash" fi done check_linux_package "uninstall" "setroubleshoot" check_linux_package "uninstall" "mctrans" else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_sysctl.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sysctl # # Check sysctl settings # # Refer to Section(s) 5.1-5.2.8,5.4.1,2 Page(s) 98-107 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 4.1.1-2,4.2.1-8,4.4.1 Page(s) 82-94 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 4.1.1-2,4.2.1-8,4.4.1.1 Page(s) 73-81,83-4 CIS RHEL 5 Benchmark v2.1. # Refer to Section(s) 1.4.1,1.5.3,3.1.1-8,3.3.1-3 Page(s) 57,65,129-142 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 7.1.1-8,7.3.1-2 Page(s) 65-76 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.5.3,3.3.1-2,3.2.1-8,3.3.1-3 Page(s) 60-1,125-6,127-35,136-8 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 3.3.1-11 Page(s) 386-436 CIS Ubuntu 24.04 Benchmark v1.0.0 # Refer to Section(s) 1.1.2,1.5.1,3,3.1.1-8,3.3.1-3 Page(s) 24-6,53,57,116-29 CIS Amazon Linux Benchmark v2.0.0 #. audit_sysctl () { print_function "audit_sysctl" string="Sysctl Configuration" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.default.secure_redirects" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.all.secure_redirects" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.icmp_echo_ignore_broadcasts" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.all.accept_redirects" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.default.accept_redirects" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.tcp_syncookies" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.tcp_max_syn_backlog" "eq" "4096" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.all.rp_filter" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.default.rp_filter" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.all.accept_source_route" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.default.accept_source_route" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.tcp_max_orphans" "eq" "256" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.all.log_martians" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.ip_forward" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.all.send_redirects" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.conf.default.send_redirects" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv4.icmp_ignore_bogus_error_responses" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv6.conf.default.accept_redirects" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv6.conf.all.accept_ra" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv6.conf.default.accept_ra" "eq" "0" "hash" check_file_value "is" "/etc/sysctl.conf" "net.ipv6.route.flush" "eq" "1" "hash" check_file_value "is" "/etc/sysctl.conf" "kernel.randomize_va_space" "eq" "2" "hash" check_append_file "/etc/security/limits.conf" "* hard core 0" "hash" check_file_perms "/etc/sysctl.conf" "0600" "root" "root" else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_virtual_memory.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_virtual_memory # # Refer to Section(s) 1.6.3 Page(s) 46 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.6.3 Page(s) 51-2 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.6.3 Page(s) 48-9 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 4.3 Page(s) 37 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.5.3 Page(s) 57 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 1.5.1 Page(s) 166-9 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_virtual_memory () { print_function "audit_virtual_memory" string="Randomised Virtual Memory Region Placement" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "Ubuntu" ]; then if [ "${os_version}" -gt 5 ]; then check_file_value "is" "/etc/sysctl.conf" "kernel.randomize_va_space" "eq" "2" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_xen.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_xen # # Turn off Xen services if they are not being used. #. audit_xen () { print_function "audit_xen" string="Xen Daemons" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for service_name in xend xendomains; do check_linux_service "${service_name}" "off" done else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_xinetd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_xinetd # # Check inetd services # # Refer to Section(s) 2.1.12-8 Page(s) 54-8 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.12-8 Page(s) 63-6 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.12-8 Page(s) 57-61 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.1.1-7 Page(s) 91-7 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 2.1.10-1 Page(s) 88-9 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.1.19 Page(s) 280-2 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_xinetd () { print_function "audit_xinetd" string="Xinetd Services" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_dir="/etc/xinetd.d" if [ -d "${check_dir}" ]; then check=$( find "${check_dir}" -type f ) if [ -n "${check}" ]; then verbose_message "Xinet Services" "check" command="grep disable \"${check_dir}/*\" | awk '{print \$3}' | grep no | head -1 | grep -c no |sed \"s/ //g\"" command_message "${command}" xinetd_check=$( eval "${command}" ) if [ "${xinetd_check}" = "1" ]; then for service_name in amanda amandaidx amidxtape auth chargen-dgram \ chargen-stream cvs daytime-dgram daytime-stream discard-dgram \ echo-dgram echo-stream eklogin ekrb5-telnet gssftp klogin krb5-telnet \ kshell ktalk ntalk rexec rlogin rsh rsync talk tcpmux-server telnet \ tftp time-dgram time-stream uucp; do check_xinetd_service "${service_name}" "disable" "yes" done else check_linux_service "xinetd" "off" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_xinetd_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_xinetd_server # # Refer to Section(s) 2.1.11 Page(s) 54 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.11 Page(s) 62 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.11 Page(s) 46-7 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.1.7 Page(s) 97 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.1.9 Page(s) 45-6 CIS SLES 11 Benchmark v1.0.0 #. audit_xinetd_server () { print_function "audit_xinetd_server" string="Xinetd Server Daemon" check_message "${string}" if [ "${os_name}" = "Linux" ]; then service_name="xinetd" check_linux_service "${service_name}" "off" if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ]; then check_linux_package "uninstall" "${service_name}" fi else na_message "${string}" fi } ================================================ FILE: modules/linux/audit_yum_conf.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_yum_conf # # Make sure GPG checks are enabled for yum so that malicious sofware can not # be installed. # # Refer to Section(s) 1.2.3 Page(s) 32 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.2.2 Page(s) 50 CIS RHEL 7 Benchmark v1.0.0 # Refer to Section(s) 1.2.3 Page(s) 34 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.1.3 Page(s) 34 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.2.3 Page(s) 46 CIS Amazon Linux Benchmark v2.0.0 #. audit_yum_conf () { print_function "audit_yum_conf" string="Yum Configuration" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ]; then check_file_value "is" "/etc/yum.conf" "gpgcheck" "eq" "1" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/login/audit_console_login.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2028 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_console_login # # Check console login # # Refer to Section(s) 6.4 Page(s) 142-3 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.4 Page(s) 165 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 6.4 Page(s) 145 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.5 Page(s) 256 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 9.3.4 Page(s) 134-5 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 6.14 Page(s) 57 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.10 Page(s) 95-6 CIS Solaris 10 Benchamrk v5.1.0 # Refer to Section(s) 5.5 Page(s) 248 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_console_login () { print_function "audit_console_login" string="Root Login to System Console" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file="/etc/default/login" check_file_value "is" "${check_file}" "CONSOLE" "eq" "/dev/console" "hash" fi if [ "${os_version}" = "11" ]; then service_name="svc:/system/console-login:terma" check_sunos_service "svc:/system/console-login:terma" "disabled" service_name="svc:/system/console-login:termb" check_sunos_service "${service_name}" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_file="/etc/securetty" if [ -f "${check_file}" ]; then string="Root Login to System Console" check_message "${string}" disable_ttys=0 console_list="" if [ "${audit_mode}" != 2 ]; then if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: ${string}" echo " lineinfile:" echo " path: ${check_file}" echo " regexp: '^tty[0-9]" echo " replace: '#\1'" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" fi device_list=$( grep '^tty[0-9]' ${check_file} ) for console_device in $device_list; do disable_ttys=1 console_list="$console_list ${console_device}" done if [ "${disable_ttys}" = 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Consoles enabled on \"$console_list\"" fix_message "ed 's/^tty[0-9].*//g' < ${check_file} | grep '[a-z]' > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "Consoles to disabled on \"$console_list\"" command="sed \"s/tty[0-9].*//g\" < \"${check_file}\" | grep '[a-z]' > \"${temp_file}\"" command_message "${command}" eval "${command}" command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "No consoles enabled on tty[0-9]*" fi fi else restore_file "${check_file}" "${restore_dir}" fi fi else na_message "${string}" fi } ================================================ FILE: modules/login/audit_failed_logins.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_failed_logins # # Check failed logins # # Refer to Section(s) 4.6 Page(s) 70-1 CIS Solaris 10 Benchmark v5.1.0 #. audit_failed_logins () { print_function "audit_failed_logins" string="Failed Login Attempts" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file_value "is" "/etc/default/login" "SYSLOG_FAILED_LOGINS" "eq" "0" "hash" check_file_value "is" "/etc/default/login" "SYSLOG" "eq" "YES" "hash" check_file_value "is" "/etc/default/su" "SYSLOG" "eq" "YES" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/login/audit_issue_banner.sh ================================================ #!/bin/sh -eu # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2129 # shellcheck disable=SC2154 # audit_issue_banner # # Check security banner # # Refer to Section(s) 8.1-2 Page(s) 149-151 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 8.1.1-2 Page(s) 172-4 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 8.1-2 Page(s) 152-4 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.7.1.1-3 Page(s) 78-83 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 11.1-2 Page(s) 142-3 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 7.4 Page(s) 25 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.7.1.1-3 Page(s) 68-73 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 1.7.1.1-6 Page(s) 75-83 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.6.1-6 Page(s) 184-95 CIS Ubuntu 24.04 Benchmark v1.0.0 # Refer to Section(s) 5.13 Page(s) 143 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 5.8 Page(s) 352-4 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_issue_banner () { print_function "audit_issue_banner" string="Security Warning Message" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "Darwin" ]; then file_list="/etc/issue /etc/motd /etc/issue.net /Library/Security/PolicyBanner.txt" else file_list="/etc/issue /etc/motd /etc/issue.net" fi for check_file in ${file_list}; do if [ -f "${check_file}" ]; then check_file_perms "${check_file}" 0644 root root command="grep -cE \"NOTICE TO USERS|UNAUTHORIZED ACCESS\" \"${check_file}\" | sed \"s/ //g\"" command_message "${command}" issue_check=$( eval "${command}" ) else issue_check=0 fi if [ "${audit_mode}" != 2 ]; then verbose_message "Security message in \"${check_file}\"" "check" if [ "${issue_check}" = 0 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "No security message in \"${check_file}\"" fi if [ "${audit_mode}" = 0 ]; then set_message "Security message in \"${check_file}\"" backup_file "${check_file}" echo "###############################################################################" > "${check_file}" echo "# NOTICE TO USERS #" >> "${check_file}" echo "# --------------- #" >> "${check_file}" echo "# This computer system is the private property of this company: #" >> "${check_file}" echo "# Whether individual, corporate or government. It is for authorized use only. #" >> "${check_file}" echo "# Users (authorized & unauthorized) have no explicit/implicit expectation of #" >> "${check_file}" echo "# privacy. #" >> "${check_file}" echo "# #" >> "${check_file}" echo "# Any or all uses of this system and all files on this system may be #" >> "${check_file}" echo "# intercepted, monitored, recorded, copied, audited, inspected, and #" >> "${check_file}" echo "# disclosed to your employer, to authorized site, government, and/or #" >> "${check_file}" echo "# law enforcement personnel, as well as authorized officials of government #" >> "${check_file}" echo "# agencies, both domestic and foreign. #" >> "${check_file}" echo "# #" >> "${check_file}" echo "# By using this system, the user expressly consents to such interception, #" >> "${check_file}" echo "# monitoring, recording, copying, auditing, inspection, and disclosure at #" >> "${check_file}" echo "# the discretion of such officials. Unauthorized or improper use of this #" >> "${check_file}" echo "# system may result in civil and criminal penalties and administrative or #" >> "${check_file}" echo "# disciplinary action, as appropriate. By continuing to use this system #" >> "${check_file}" echo "# you indicate your awareness of and consent to these terms and conditions. #" >> "${check_file}" echo "# #" >> "${check_file}" echo "# LOG OFF IMMEDIATELY if you do not agree to the conditions in this warning. #" >> "${check_file}" echo "###############################################################################" >> "${check_file}" # Alternate message # echo "---------------------------------------------------------------------------------" >> "${check_file}" # echo "UNAUTHORIZED ACCESS TO THIS DEVICE IS PROHIBITED " >> "${check_file}" # echo "You must have explicit, authorized permission to access or configure this device." >> "${check_file}" # echo "Unauthorized attempts and actions to access or use this system may result in " >> "${check_file}" # echo "civil and/or criminal penalties. " >> "${check_file}" # echo "All activities performed on this device are logged and monitored. " >> "${check_file}" # echo "---------------------------------------------------------------------------------" >> "${check_file}" echo "" >> "${check_file}" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Security message in \"${check_file}\"" fi fi else restore_file "${check_file}" "${restore_dir}" fi done else na_message "${string}" fi } ================================================ FILE: modules/login/audit_login_delay.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_login_delay # # Refer to Section(s) 6.10 Page(s) 53-4 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.6 Page(s) 91 CIS Solaris 10 Benchmark v5.1.0 #. audit_login_delay () { print_function "audit_login_delay" string="Delay between Failed Login Attempts" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/default/login" "SLEEPTIME" "eq" "4" "hash" else na_message "${string}" fi } ================================================ FILE: modules/login/audit_login_details.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_login_details # # Refer to Section 6.1.1 Page(s) 72-73 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section 2.10.4 Page(s) 226-8 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_login_details () { print_function "audit_login_details" string="Login display details" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_bool "/Library/Preferences/com.apple.loginwindow" "SHOWFULLNAME" "yes" else na_message "${string}" fi } ================================================ FILE: modules/login/audit_login_guest.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_login_guest # # Refer to Section 1.4.2.7 Page(s) CIS Apple OS X 10.6 Benchmark v1.0.0 # Refer to Section 6.1.3 Page(s) 156-7 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section 2.12.1 Page(s) 242-5 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_login_guest () { print_function "audit_login_guest" string="Guest login" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_bool "/Library/Preferences/com.apple.loginwindow.plist" "GuestEnabled" "no" check_dscl "/Users/Guest" "AuthenticationAuthority" ";basic;" check_dscl "/Users/Guest" "passwd" "*" check_dscl "/Users/Guest" "UserShell" "/sbin/nologin" else na_message "${string}" fi } ================================================ FILE: modules/login/audit_login_records.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_login_records # # Refer to Section(s) 4.5 Page(s) 69-70 CIS Solaris 10 Benchmark v5.1.0 #. audit_login_records () { print_function "audit_login_records" string="Login Records" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then audit_logadm_value "loginlog" "none" fi else na_message "${string}" fi } ================================================ FILE: modules/login/audit_login_root.sh ================================================ #!/bin/sh # -> Needs fixing # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_login_root # # Check root login # # Refer to Section(s) 5.7 Page(s) 135 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 5.6 Page(s) 348-9 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_login_root () { print_function "audit_login_root" string="Root login" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_dscl "/Users/root" "AuthenticationAuthority" "No such key: AuthenticationAuthority" else na_message "${string}" fi } ================================================ FILE: modules/login/audit_login_warning.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_login_warning # # An access warning may reduce a casual attacker's tendency to target the system. # Access warnings may also aid in the prosecution of an attacker by evincing the # attacker's knowledge of the system's private status, acceptable use policy, and # authorization requirements. # # Refer to Section(s) 5.19 Page(s) 67-8 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 5.12 Page(s) 142 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.10.1 Page(s) 226-8 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_login_warning () { print_function "audit_login_warning" string="Login message warning" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_value "com.apple.loginwindow" "LoginwindowText" "Authorised users only" else na_message "${string}" fi } ================================================ FILE: modules/login/audit_remote_login.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_remote_login # # Check remote login # # Refer to Section(s) 2.4.5 Page(s) 42-3 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.3.3.5 Page(s) 100-3 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_remote_login () { print_function "audit_remote_login" string="Remote Login" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_systemsetup "getremotelogin" "off" else na_message "${string}" fi } ================================================ FILE: modules/login/audit_retry_limit.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_retry_limit # # Check retry limit for account lockout # # Refer to Section(s) 1.2.1-6 Page(s) 26-31 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 6.15 Page(s) 57-9 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.11 Page(s) 96-7 CIS Solaris 10 Benchmark v5.1.0 #. audit_retry_limit () { print_function "audit_retry_limit" string="Retry Limit for Account Lockout" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_chsec "/etc/security/login.cfg" "default" "logininterval" "300" check_chsec "/etc/security/login.cfg" "default" "logindisable" "10" check_chsec "/etc/security/login.cfg" "default" "loginreenable" "360" check_chsec "/etc/security/login.cfg" "usw" "logintimeout" "30" check_chsec "/etc/security/login.cfg" "default" "logindelay" "10" check_chsec "/etc/security/user" "default" "loginretries" "3" fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_file_value "is" "/etc/default/login" "RETRIES" "eq" "3" "hash" check_file_value "is" "/etc/security/policy.conf" "LOCK_AFTER_RETRIES" "eq" "YES" "hash" if [ "${os_version}" = "11" ]; then svcadm "restart" "svc:/system/name-service/cache" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/login/audit_security_banner.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_security_banner # # Check Security banner # # Refer to Section(s) 7.4 Page(s) 25 CIS CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.11.11,2.12.12 Page(s) 198,216 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 8.1.1 Page(s) 172-3 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 8.1 Page(s) 152-3 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.7.1.4-6 Page(s) 84-8 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 11.1 Page(s) 142-3 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 8.1 Page(s) 68-9 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 8.1 Page(s) 111-2 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 1.7.1.4-6 Page(s) 74-6 CIS Amazon Linux Benchmark v2.0.0 #. audit_security_banner () { print_function "audit_security_banner" string="Warnings for Standard Login Services" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then user_name="bin" group_name="bin" else user_name="root" group_name="root" fi check_file="/etc/motd" check_file_exists "${check_file}" "yes" if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0644" "${user_name}" "${group_name}" fi check_file="/etc/issue" check_file_exists "${check_file}" "yes" if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0644" "${user_name}" "${group_name}" fi else na_message "${string}" fi } ================================================ FILE: modules/login/audit_serial_login.sh ================================================ #!/bin/sh # shellcheck disable=SC2034 # shellcheck disable=SC1090 # shellcheck disable=SC2154 # audit_serial_login # # Refer to Section(s) 3.1 Page(s) 9 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.12.1 Page(s) 206-7 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 6.1 Page(s) 46-7 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.2 Page(s) 87-8 CIS Solaris 10 Benchmark v5.1.0 #. audit_serial_login () { print_function "audit_serial_login" string="Login on Serial Ports" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then command="lsitab –a | grep \"on:/usr/sbin/getty\" | awk '{print \$2}'" command_message "${command}" tty_list=$( eval "${command}" ) if [ -z "${tty_list}" ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "Serial port logins disabled" fi if [ "${audit_mode}" = 2 ]; then command="lsitab –a | grep \"/usr/sbin/getty\" | awk '{print \$2}'" command_message "${command}" tty_list=$( eval "${command}" ) for tty_name in ${tty_list}; do log_file="${restore_dir}/${tty_name}" if [ -f "${log_file}" ]; then command="cat \"${log_file}\"" command_message "${command}" previous_value=$( eval "${command}" ) restore_message "TTY \"${tty_name}\" to \"${previous_value}\"" command="chitab \"${previous_value} ${tty_name}\"" command_message "${command}" eval "${command}" fi done fi else for tty_name in ${tty_list}; do if [ "${audit_mode}" != 2 ]; then log_file="${work_dir}/${tty_name}" command="lsitab -a | grep \"on:/usr/sbin/getty\" | grep \"${tty_name}\"" command_message "${command}" actual_value=$( eval "${command}" ) command="echo \"${actual_value}\" | sed 's/on/off/g'" command_message "${command}" new_value=$( eval "${command}" ) if [ "${audit_mode}" = 1 ]; then inc_insecure "Serial port logins not disabled on \"${tty_name}\"" fix_message "chitab \"${new_value}\"" fi if [ "${audit_mode}" = 0 ]; then command="echo \"${actual_value}\" > \"${log_file}\"" command_message "${command}" eval "${command}" command="chitab \"${new_value} ${tty_name}\"" command_message "${command}" eval "${command}" fi else log_file="${restore_dir}/${tty_name}" if [ -f "${log_file}" ]; then command="cat \"${log_file}\"" command_message "${command}" previous_value=$( eval "${command}" ) verbose_message "Restoring: TTY \"${tty_name}\" to \"${previous_value}\"" command="chitab \"${previous_value} ${tty_name}\"" command_message "${command}" eval "${command}" fi fi done fi fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" != "11" ]; then command="pmadm -L | grep -E \"ttya|ttyb\" | cut -f4 -d \":\" | grep -c \"ux\"" command_message "${command}" serial_test=$( eval "${command}" ) log_file="${work_dir}/pmadm.log" command="expr \"$serial_test\" : \"2\"" command_message "${command}" serial_check=$( eval "${command}" ) if [ "${serial_check}" = "1" ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "Serial port logins disabled" fi else if [ "${audit_mode}" = 1 ]; then inc_insecure "Serial port logins not disabled" fix_message "pmadm -d -p zsmon -s ttya" fix_message "pmadm -d -p zsmon -s ttyb" fi if [ "${audit_mode}" = 0 ]; then set_message "Serial port logins to disabled" command="echo \"ttya,ttyb\" >> \"${log_file}\"" command_message "${command}" eval "${command}" command="pmadm -d -p zsmon -s ttya" command_message "${command}" eval "${command}" command="pmadm -d -p zsmon -s ttyb" command_message "${command}" eval "${command}" fi fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/pmadm.log" if [ -f "${restore_file}" ]; then restore_message "Serial port logins to enabled" command="pmadm -e -p zsmon -s ttya" command_message "${command}" eval "${command}" command="pmadm -e -p zsmon -s ttyb" command_message "${command}" eval "${command}" fi fi fi fi if [ "${os_name}" = "FreeBSD" ]; then check_file="/etc/ttys" check_string="dialup" command="grep \"${check_string}\" \"${check_file}\" |awk '{print \$5}'" command_message "${command}" ttys_test=$( eval "${command}" ) if [ "${ttys_test}" != "off" ]; then if [ "${audit_mode}" != 2 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Serial port logins not disabled" fi if [ "${audit_mode}" = 2 ]; then set_message "Serial port logins to disabled" backup_file "${check_file}" temp_file="${temp_dir}/ttys_${check_string}" command="awk '(\\$4 == \"dialup\") { \\$5 = \"off\" } { print }' < \"${check_file}\" > \"${temp_file}\"" command_message "${command}" eval "${command}" command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" fi else restore_file "${check_file}" "${restore_dir}" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Serial port logins disabled" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/login/audit_sulogin.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sulogin # # Check single user mode requires password # # Refer to Section(s) 1.5.4-5 Page(s) 43-44 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.4.3 Page(s) 60 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 3.2 Page(s) 9 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 3.4 Page(s) 33-4 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.5.4-5 Page(s) 48-9 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.5.4-5 Page(s) 45-6 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.4.2-3 Page(s) 51-2 CIS Amazon Linux Benchmark v2.0.0 #. audit_sulogin () { print_function "audit_sulogin" string="Single User Mode Requires Password" check_message "${string}" temp_file="${temp_dir}/audit_sulogin" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${os_name}" = "FreeBSD" ]; then check_file="/etc/ttys" check_string="console" command="grep \"${check_string}\" \"${check_file}\" |awk '{print \$5}'" command_message "${command}" ttys_test=$( eval "${command}" ) if [ "${ttys_test}" != "insecure" ]; then if [ "${audit_mode}" != 2 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Single user mode does not require a password" fi if [ "${audit_mode}" = 2 ]; then set_message "Single user mode to require a password" backup_file "${check_file}" lock_command="awk '($4 == \"console\") { $5 = \"insecure\" } { print }' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else restore_file "${check_file}" "${restore_dir}" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Single user login requires password" fi fi fi if [ "${os_name}" = "Linux" ] && [ "${os_vendor}" = "Red" ] && [ "${os_version}" = "7" ]; then check_file_value "is" "/usr/lib/systemd/system/rescue.service" "ExecStart" "eq" "-/bin/sh -c \"/sbin/sulogin; /usr/bin/systemctl --fail --no-block default\"" "hash" "2" "blockdefault" check_file_value "is" "/usr/lib/systemd/system/emergency.service" "ExecStart" "eq" "-/bin/sh -c \"/sbin/sulogin; /usr/bin/systemctl --fail --no-block default\"" "hash" "2" "blockdefault" fi if [ "${os_name}" = "Linux" ]; then check_file="/etc/inittab" if [ -f "${check_file}" ]; then command="grep -l sulogin \"${check_file}\"" command_message "${command}" sulogin_check=$( eval "${command}" ) if [ -z "$sulogin_check" ]; then lock_message="Single user mode to require authentication" lock_command="awk '{ print }; /^id:[0123456sS]:initdefault:/ { print \"~~:S:wait:/sbin/sulogin\" }' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm $temp_file" if [ "${audit_mode}" = 1 ]; then inc_insecure "No Authentication required for single usermode" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Single usermode requires authentication" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi check_file_perms "${check_file}" "0600" "root" "root" fi check_file="/etc/sysconfig/init" check_file_value "is" "/etc/sysconfig/init" "SINGLE" "eq" "/sbin/sulogin" "hash" check_file_value "is" "/etc/sysconfig/init" "PROMPT" "eq" "no" "hash" check_file_perms "/etc/sysconfig/init" "0600" "root" "root" fi check_file_value "is" "/etc/sysconfig/boot" "PROMPT_FOR_CONFIRM" "eq" "no" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/login/audit_xlogin.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_xlogin # # Refer to Section(s) 7.7 Page(s) 26 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.3.4 Page(s) 38 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 2.1 Page(s) 15 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 2.1.3 Page(s) 19 CIS Solaris 10 Benchmark v5.1.0 #. audit_xlogin () { print_function "audit_xlogin" string="X Windows" check_message "${string}" temp_file="${temp_dir}/audit_xlogin" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "AIX" ]; then check_message "CDE Startup" "check" check_itab "dt" "off" fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_message "XDMCP Listening" fi if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/application/gdm2-login" "disabled" check_sunos_service "svc:/application/graphical-login/cde-login" "disabled" fi if [ "${os_version}" = "11" ]; then check_sunos_service "svc:/application/graphical_login/gdm:default" "disabled" fi if [ "${os_version}" = "10" ]; then check_sunos_service "dtlogin" "disabled" fi fi if [ "${os_name}" = "FreeBSD" ]; then check_file="/etc/ttys" check_string="nodaemon" command="grep ${check_string} ${check_file} | awk '{print \$5}'" command_message "${command}" ttys_test=$( eval "${command}" ) secure_string="X Wrapper is disabled" insecure_string="X Wrapper is not disabled" check_message "${secure_string}" "check" if [ "${ttys_test}" != "on" ]; then if [ "${audit_mode}" != 2 ]; then if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${secure_string}" echo " lineinfile:" echo " path: ${check_file}" echo " regexp: '/xdm -nodaemon/s/off/on/'" echo " when: ansible_facts['ansible_system'] == '${os_name}'" fi if [ "${audit_mode}" = 1 ]; then inc_insecure "${insecure_string}" fi if [ "${audit_mode}" = 2 ]; then backup_file "${check_file}" lock_message="X wrapper to disabled" lock_command="sed -e '/xdm -nodaemon/s/off/on/' ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else restore_file "${check_file}" "${restore_dir}" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "${secure_string}" fi fi fi if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then check_file="/etc/X11/xdm/Xresources" if [ -f "${check_file}" ]; then check_message "X Security Message" if [ "${audit_mode}" != 2 ]; then command="grep 'private system' \"${check_file}\"" command_message "${command}" greet_check=$( eval "${command}" ) if [ -z "${greet_check}" ]; then check_message "File ${check_file} for security message" greet_mesg="This is a private system --- Authorized use only!" lock_command="awk '/xlogin\*greeting:/ { print GreetValue; next }; { print }' GreetValue=\"${greet_mesg}\" < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${audit_mode}" = 1 ]; then inc_insecure "File ${check_file} does not have a security message" fix_message "${lock_command}" else backup_file "${check_file}" lock_message="Security message in ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else inc_secure "File \"${check_file}\" has security message" fi else restore_file "${check_file}" "${restore_dir}" fi fi check_file="/etc/X11/xdm/kdmrc" if [ -f "${check_file}" ]; then verbose_message "X Security Message" "check" if [ "${audit_mode}" != 2 ]; then command="grep -c 'private system' ${check_file}" command_message "${command}" greet_check=$( eval "${command}" ) greet_mesg="This is a private system --- Authorized USE only!" if [ "${greet_check}" != 1 ]; then verbose_message "File ${check_file} for security message" lock_message="cat ${check_file} |awk '/GreetString=/ { print \"GreetString=\" GreetString; next }; { print }' GreetString=\"${greet_mesg}\" > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${audit_mode}" = 1 ]; then inc_insecure "File ${check_file} does not have a security message" fix_message "${lock_command}" else backup_file "${check_file}" lock_message="Security message in ${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else inc_secure "File ${check_file} has security message" fi else restore_file "${check_file}" "${restore_dir}" fi fi check_file="/etc/X11/xdm/Xservers" if [ -f "${check_file}" ]; then verbose_message "X Listening" if [ "${audit_mode}" != 2 ]; then command="grep -c 'nolisten tcp' \"${check_file}\"" command_message "${command}" greet_check=$( eval "${command}" ) if [ "${greet_check}" != 1 ]; then verbose_message "For X11 nolisten directive in file \"${check_file}\"" "check" lock_command_1="awk '( \$1 !~ /^#/ && \$3 == \"/usr/X11R6/bin/X\" ) { \$3 = \$3 \" -nolisten tcp\" }; { print }' < ${check_file} > ${temp_file}" lock_command_2="awk '( \$1 !~ /^#/ && \$3 == \"/usr/bin/X\" ) { \$3 = \$3 \" -nolisten tcp\" }; { print }' < ${check_file} > ${temp_file}" lock_command_3="cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${audit_mode}" = 1 ]; then inc_insecure "X11 nolisten directive not found in file \"${check_file}\"" fix_message "${lock_command_1}" fix_message "${lock_command_2}" fix_message "${lock_command_3}" else backup_file "${check_file}" lock_message="Security message in file \"${check_file}\"" run_lockdown "${lock_command_1}" "${lock_message}" "sudo" run_lockdown "${lock_command_2}" "${lock_message}" "sudo" run_lockdown "${lock_command_3}" "${lock_message}" "sudo" fi else inc_secure "X11 nolisten directive found in file \"${check_file}\"" fi else restore_file "${check_file}" "${restore_dir}" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/logs/audit_debug_logging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_debug_logging # # Connections to server should be logged so they can be audited in the event # of and attack. #. audit_debug_logging () { print_function "audit_debug_logging" string="Connection Logging" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then audit_logadm_value "connlog" "daemon.debug" fi else na_message "${string}" fi } ================================================ FILE: modules/logs/audit_inetd_logging.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_inetd_logging # # Check inetd logging # # Refer to Section(s) 4.1 Page(s) 66-7 CIS Solaris 10 Benchmark v5.1.0 #. audit_inetd_logging () { print_function "audit_inetd_logging" string="Logging for inetd" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/default/syslogd" "LOG_FROM_REMOTE" "eq" "NO" "hash" if [ "${os_version}" = "10" ]; then check_command_value "inetadm" "tcp_trace" "TRUE" "tcp" fi if [ "${os_version}" = "9" ]; then check_file_value "is" "/etc/default/inetd" "ENABLE_CONNECTION_LOGGING" "eq" "YES" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/logs/audit_logadm_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2028 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2154 # audit_logadm_value # # Enable Debug Level Daemon Logging. Improved logging capability. # # Refer to Section(s) 4.3 Page(s) 67-8 CIS Solaris 10 Benchmark v5.1.0 #. audit_logadm_value () { print_function "audit_logadm_value" string="Debug Level Daemon Logging" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then log_name="${1}" log_facility="${2}" check_file="/etc/logadm.conf" command="logadm -V | grep -v '^#' | grep \"${log_name}\"" command_message "${command}" check_log=$( eval "${command}" ) log_file="/var/log/${log_name}" if [ -z "$log_check" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Logging for \"${log_name}\" not enabled" fix_message "logadm -w ${log_name} -C 13 -a 'pkill -HUP syslogd' ${log_file}" fix_message "svcadm refresh svc:/system/system-log" else if [ "${audit_mode}" = 0 ]; then set_message "Syslog to capture \"${log_facility}\"" fi backup_file "${check_file}" if [ "${log_facility}" != "none" ]; then check_file="/etc/syslog.conf" if [ ! -f "${work_dir}${check_file}" ]; then echo "Saving: File ${check_file} to ${work_dir}${check_file}" command="find \"${check_file}\" | cpio -pdm \"${work_dir}\" 2> /dev/null" command_message "${command}" eval "${command}" fi fi echo "${log_facility}\t\t\t${log_file}" >> "${check_file}" touch "${log_file}" chown root:root "${log_file}" if [ "${log_facility}" = "none" ]; then command="logadm -w \"${log_name}\" -C 13 \"${log_file}\"" command_message "${command}" eval "${command}" else command="logadm -w \"${log_name}\" -C 13 -a 'pkill -HUP syslogd' \"${log_file}\"" command_message "${command}" eval "${command}" svcadm refresh svc:/system/system-log fi fi if [ "${audit_mode}" = 2 ]; then if [ -f "${restore_dir}/${check_file}" ]; then cp -p "${restore_dir}/${check_file}" "${check_file}" if [ "${os_version}" != "11" ]; then command="pkgchk -f -n -p ${check_file} 2> /dev/null" command_message "${command}" eval "${command}" else command="pkg fix \$( pkg search ${check_file} | grep pkg | awk '{print \$4}' )" command_message "${command}" eval "${command}" fi fi if [ "${log_facility}" = "none" ]; then check_file="/etc/syslog.conf" if [ -f "${restore_dir}/${check_file}" ]; then cp -p "${restore_dir}/${check_file}" "${check_file}" if [ "${os_version}" != "11" ]; then command="pkgchk -f -n -p \"${check_file}\" 2> /dev/null" command_message "${command}" eval "${command}" else command="pkg fix \$( pkg search \"${check_file}\" | grep pkg | awk '{print \$4}' )" command_message "${command}" eval "${command}" fi fi svcadm refresh svc:/system/system-log fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Logging for \"${log_name}\" already enabled" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/logs/audit_logrotate.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2154 # audit_logrotate # # Check logrotate # # Refer to Section(s) 4.3 Page(s) 97 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 5.3 Page(s) 120-1 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 4.3 Page(s) 208 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 8.4 Page(s) 113-4 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 4.3 Page(s) 191 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.1.3.8 Page(s) 787-8 CIS Ubuntu LTS 24.04 Benchmark v1.0.0 #. audit_logrotate () { print_function "audit_logrotate" string="Log Rotate Configuration" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for check_file in /etc/logrotate.d/syslog /etc/logrotate.d/rsyslog; do if [ -f "${check_file}" ]; then if [ "${audit_mode}" != 2 ]; then if [ "${os_vendor}" = "SuSE" ]; then search_string="/var/log/warn /var/log/messages /var/log/allmessages /var/log/localmessages /var/log/firewall /var/log/acpid /var/log/NetworkManager /var/log/mail /var/log/mail.info /var/log/mail.warn /var/log/mail.err /var/log/news/news.crit /var/log/news/news.err /var/log/news/news.notice" else search_string="/var/log/messages /var/log/secure /var/log/maillog /var/log/spooler /var/log/boot.log /var/log/cron" fi command="grep \"${search_string}\" \"${check_file}\" | sed 's/ {//g'" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" != "${search_string}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Log rotate is not configured for ${search_string}" fix_message "cat ${check_file} |sed 's,.*{,${search_string} {,' > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" echo "Removing: Configuring logrotate" command="sed \"s,.*{,${search_string} {,\" \"${check_file}\" > \"${temp_file}\"" command_message "${command}" eval "${command}" command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Log rotate is configured" fi fi else restore_file "${check_file}" "${restore_dir}" fi fi done else na_message "${string}" fi } ================================================ FILE: modules/mail/audit_email_daemons.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_email_daemons # # Check email daemons # # Refer to Section(s) 3.12 Page(s) 67 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.2.11 Page(s) 111 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 3.12 Page(s) 79-80 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 6.11 Page(s) 60 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.2.11 Page(s) 111 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.8 Page(s) 247-9 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_email_daemons () { print_function "audit_email_daemons" string="Mail Daemons" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for service_name in cyrus imapd qpopper dovecot; do check_linux_service "${service_name}" "off" check_linux_package "uninstall" "${service_name}" done else na_message "${string}" fi } ================================================ FILE: modules/mail/audit_exim.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_exim # # Check exim # # Refer to Section(s) 1.5.1 Page(s) 88-9 CIS Ubuntu 22.04 Benchmark v1.0.0 #. audit_exim () { print_function "audit_exim" string="Exim" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_file="/etc/exim4/update-exim4.conf" if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "dc_eximconfig_configtype" "eq" "'local'" "hash" check_file_value "is" "${check_file}" "dc_local_interfaces" "eq" "'127.0.0.1 ; ::1'" "hash" check_file_value "is" "${check_file}" "dc_readhost" "eq" "''" "hash" check_file_value "is" "${check_file}" "dc_relay_domains" "eq" "''" "hash" check_file_value "is" "${check_file}" "dc_minimaldns" "eq" "'false'" "hash" check_file_value "is" "${check_file}" "dc_relay_nets" "eq" "''" "hash" check_file_value "is" "${check_file}" "dc_smarthost" "eq" "''" "hash" check_file_value "is" "${check_file}" "dc_use_split_config" "eq" "'false'" "hash" check_file_value "is" "${check_file}" "dc_hide_mailname" "eq" "''" "hash" check_file_value "is" "${check_file}" "dc_mailname_in_oh" "eq" "'true'" "hash" check_file_value "is" "${check_file}" "dc_localdelivery" "eq" "'mail_spool'" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/mail/audit_postfix_daemon.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_postfix_daemon # # Refer to Section(s) 3.16 Page(s) 69-70 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.2.15 Page(s) 115-6 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 2.2.15 Page(s) 107-8 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.15 Page(s) 115-6 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.21 Page(s) 285-7 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_postfix_daemon () { print_function "audit_postfix_daemon" string="Postfix Daemon" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "SuSE" ]; then check_file_value "is" "/etc/sysconfig/mail" "SMTPD_LISTEN_REMOTE" "eq" "no" "hash" fi if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 24 ]; then check_file_value "is" "/etc/postfix/main.cf" "inet_interfaces" "eq" "loopbank-only" "hash" else check_file_value "is" "/etc/postfix/main.cf" "inet_interfaces" "eq" "localhost" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/mail/audit_sendmail_aliases.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sendmail_aliases # # Make sure sendmail aliases are configured appropriately. # Remove decode/uudecode alias #. audit_sendmail_aliases () { print_function "audit_sendmail_aliases" string="Sendmail Aliases" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then disable_value "/etc/aliases" "decode" "hash" check_file_perms "/etc/aliases" "0644" "root" "root" else na_message "${string}" fi } ================================================ FILE: modules/mail/audit_sendmail_daemon.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sendmail_daemon # # Check sendmail daemon settings # # Refer to Section(s) 3.16 Page(s) 82 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.16 Page(s) 72-3 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 3.5 Page(s) 10 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 6.15 Page(s) 62-3 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.3.6 Page(s) 40-1 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 2.2 Page(s) 15-6 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 2.1.4 Page(s) 19-20 CIS Solaris 10 Benchmark v5.1.0 #. audit_sendmail_daemon() { print_function "audit_sendmail_daemon" string="Sendmail Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "$sendmail_disable" = "yes" ]; then if [ "${os_name}" = "AIX" ]; then check_rctcp "sendmail" "off" fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/smtp:sendmail" "disabled" fi if [ "${os_version}" = "10" ]; then check_sunos_service "sendmail" "disabled" fi if [ "${os_version}" = "9" ] || [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_file_value "is" "/etc/default/sendmail" "QUEUEINTERVAL" "eq" "15m" "hash" check_append_file "/etc/default/sendmail" "MODE=" "hash" else check_initd_service "sendmail" "disable" check_file="/var/spool/cron/crontabs/root" check_string="0 * * * * /usr/lib/sendmail -q" check_append_file "${check_file}" "${check_string}" "hash" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "sendmail" "off" check_file_value "is" "/etc/sysconfig/sendmail" "DAEMON" "eq" "no" "hash" check_file_value "is" "/etc/sysconfig/sendmail" "QUEUE" "eq" "1h" "hash" fi if [ "${os_name}" = "FreeBSD" ]; then check_file="/etc/rc.conf" if [ "${os_version}" -lt 5 ]; then check_file_value "is" "/etc/rc.conf" "sendmail_enable" "eq" "NONE" "hash" else if [ "${os_version}" -gt 5 ]; then if [ "${os_version}" = "5" ] && [ "${os_update}" = "0" ]; then check_file_value "is" "/etc/rc.conf" "sendmail_enable" "eq" "NONE" "hash" else check_file_value "is" "/etc/rc.conf" "sendmail_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "sendmail_submit_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "sendmail_outbound_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "sendmail_msp_queue_enable" "eq" "NO" "hash" fi fi fi fi fi if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then check_file="/etc/mail/sendmail.cf" if [ -f "${check_file}" ]; then verbose_message "Sendmail Configuration" search_string="Addr=127.0.0.1" if [ "${audit_mode}" != 2 ]; then verbose_message "Mail transfer agent is running in local-only mode" command="grep -v '^#' \"${check_file}\" | grep \"O DaemonPortOptions\" | awk '{print \$3}' | grep \"${search_string}\"" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" = "${search_string}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Mail transfer agent is not running in local-only mode" fix_message "cp ${check_file} ${temp_file}" fix_message "cat ${temp_file} |awk 'O DaemonPortOptions=/ { print \"O DaemonPortOptions=Port=smtp, Addr=127.0.0.1, ansible_value=MTA\"; next} { print }' > ${check_file}" fix_message "rm ${temp_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "Mail transfer agent to run in local-only mode" command="cp \"${check_file}\" \"${temp_file}\"" command_message "${command}" eval "${command}" command="awk 'O DaemonPortOptions=/ { print \"O DaemonPortOptions=Port=smtp, Addr=127.0.0.1, ansible_value=MTA\"; next} { print }' < \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Mail transfer agent is running in local-only mode" fi fi else restore_file "${check_file}" "${restore_dir}" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/mail/audit_sendmail_greeting.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sendmail_greeting # # Check sendmail greeting #. audit_sendmail_greeting () { print_function "audit_sendmail_greeting" string="Sendmail Greeting" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then check_file="/etc/mail/sendmail.cf" if [ -f "${check_file}" ]; then search_string="v/" if [ "${audit_mode}" != 2 ]; then command="grep -v \"^#\" \"${check_file}\" | grep \"O SmtpGreetingMessage\" | awk '{print \$4}' | grep \"${search_string}\"" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" = "${search_string}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Found version information in sendmail greeting" fix_message "cp ${check_file} ${temp_file}" fix_message "awk '/O SmtpGreetingMessage=/ { print \"O SmtpGreetingMessage=Mail Server Ready; \$b\"; next} { print }' < ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "Sendmail greeting to have no version information" command="cp \"${check_file}\" \"${temp_file}\"" command_message "${command}" eval "${command}" command="awk '/O SmtpGreetingMessage=/ { print \"O SmtpGreetingMessage=Mail Server Ready; \$b\"; next} { print }' < \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = "1" ]; then inc_secure "No version information in sendmail greeting" fi fi else restore_file "${check_file}" "${restore_dir}" fi disable_value "${check_file}" "O HelpFile" "hash" if [ "${audit_mode}" != 2 ]; then check_value=$( grep -v '^#' "${check_file}" | grep "${search_string}" ) if [ "${check_value}" = "${search_string}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Found help information in sendmail greeting" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "Sendmail to have no help information" command="cp \"${check_file}\" \"${temp_file}\"" command_message "${command}" eval "${command}" command="sed 's/^O HelpFile=/#O HelpFile=/' < \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = "1" ]; then inc_secure "No help information in sendmail greeting" fi fi else restore_file "${check_file}" "${restore_dir}" fi check_file_perms "${check_file}" "0444" "root" "root" fi else na_message "${string}" fi } ================================================ FILE: modules/mounts/audit_mount_fdi.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2129 # shellcheck disable=SC2154 # audit_mount_fdi # # User mountable file systems on Linux. # # This can stop possible vectors of attack and escalated privileges. #. audit_mount_fdi () { print_function "audit_mount_fdi" string="User Mountable Filesystems" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_dir="/usr/share/hal/fdi/95userpolicy" if [ -e "${check_dir}" ]; then check_file="${check_dir}/floppycdrom.fdi" else check_dir="/usr/share/hal/fdi/policy/20thirdparty" check_file="${check_dir}/floppycdrom.fdi" fi if [ -d "${check_dir}" ]; then if [ ! -f "${check_file}" ]; then touch "${check_file}" chmod 640 "${check_file}" chown root:root "${check_file}" fi fi if [ -f "${check_file}" ]; then if [ "${audit_mode}" != "2" ]; then command="grep -v \"Default policies\" \"${check_file}\" | head -1 | wc -l | sed \"s/ //g\"" command_message "${command}" fdi_check=$( eval "${command}" ) if [ "$fdi_check" = 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "User mountable filesystems enabled" fix_message "echo ' >' > ${temp_file}" fix_message "echo '' >> ${temp_file}" fix_message "echo ' ' >> ${temp_file}" fix_message "echo ' ' >> ${temp_file}" fix_message "echo ' ' >> ${temp_file}" fix_message "echo ' true' >> ${temp_file}" fix_message "echo ' true' >> ${temp_file}" fix_message "echo ' ' >> ${temp_file}" fix_message "echo ' ' >> ${temp_file}" fix_message "echo '' >> ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" "fix" fi if [ "${audit_mode}" = 0 ]; then verbose_message "Disabling user mountable filesystems" "set" backup_file "${check_file}" echo ' >' > "${temp_file}" echo '' >> "${temp_file}" echo ' ' >> "${temp_file}" echo ' ' >> "${temp_file}" echo ' ' >> "${temp_file}" echo ' true' >> "${temp_file}" echo ' true' >> "${temp_file}" echo ' ' >> "${temp_file}" echo ' ' >> "${temp_file}" echo '' >> "${temp_file}" cat "${temp_file}" > "${check_file}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "User mountable filesystems disabled" fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi fi fi fi check_file_perms "${check_file}" "0640" "root" "root" else na_message "${string}" fi } ================================================ FILE: modules/mounts/audit_mount_nodev.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_mount_nodev # # Check nodev on mounts # # Refer to Section(s) 1.1.2,4,10,11,14,16 Page(s) 15-25 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.1.2,4,10,11,14,16 Page(s) 16-26 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.1.2,4,10,11,14,16 Page(s) 16-26 CIS RHEL 6 Benchmark v1.0.0 # Refer to Section(s) 1.1.3,8,14,15,18 Page(s) 33,39,40,43 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 1.1.3,8,14,15,18 Page(s) 27,31,37-8,41 CIS Ubuntu LTS 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.1.2.[1-7].2 Page(s) 80-1,89-90, # 99-100,107-8 # 123-4,132-3 CIS Ubuntu LTS 24.04 Benchmark v1.0.0 # Refer to Section(s) 2.2,4,10,11,14,16 Page(s) 15-25 CIS SLES 11 Benchmark v1.2.0 # Refer to Section(s) 1.1.8,14,17 Page(s) 32,38-9 CIS Amazon Linux Benchmark v2.0.0 #. audit_mount_nodev () { print_function "audit_mount_nodev" string="File Systems mounted with nodev" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_file="/etc/fstab" if [ -e "${check_file}" ]; then if [ "${audit_mode}" != "2" ]; then command="grep -v \"^#\" \"${check_file}\" | grep -E \"ext2|ext3|swap|tmpfs\" | grep -v '/ ' | grep -cv '/boot' | sed \"s/ //g\"" command_message "${command}" nodev_check=$( eval "${command}" ) if [ "$nodev_check" = 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Found filesystems that should be mounted nodev" fix_message "cat ${check_file} | awk '( \$3 ~ /^ext[2,3,4]|tmpfs$/ && \$2 != \"/\" ) { \$4 = \$4 \",nodev\" }; { printf \"%-26s %-22s %-8s %-16s %-1s %-1s\\\n\",\$1,\$2,\$3,\$4,\$5,\$6 }' > \"${temp_file}\"" fix_message "cat \"${temp_file}\" > \"${check_file}\"" fix_message "rm \"${temp_file}\"" fi if [ "${audit_mode}" = 0 ]; then set_message "Setting nodev on filesystems" backup_file "${check_file}" command="awk '( \$3 ~ /^ext[2,3,4]|tmpf$/ && \$2 != \"/\" ) { \$4 = \$4 \",nodev\" }; { printf \"%-26s %-22s %-8s %-16s %-1s %-1s\\\n\",\$1,\$2,\$3,\$4,\$5,\$6 }' < \"${check_file}\" > \"${temp_file}\"" command_message "${command}" eval "${command}" command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "No filesystem that should be mounted with nodev" fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi fi fi check_file_perms "${check_file}" "0644" "root" "root" fi else na_message "${string}" fi } ================================================ FILE: modules/mounts/audit_mount_noexec.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_mount_noexec # # Check No-exec on mounts # # Refer to Section(s) 1.1.4 Page(s) 14-5 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.1.4 Page(s) 17-8 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.1.10,17,20 Page(s) 35,42,45 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 2.4 Page(s) 16-7 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.1.2.[1-7].4 Page(s) 84-5,93-4, # 118-9,127-8 # 136-7 CIS Ubuntu LTS 24.04 Benchmark v1.0.0 # Refer to Section(s) 1.1.3,5,10,17 Page(s) 27,29,34,41 CIS Amazon Linux Benchmark v2.0.0 #. audit_mount_noexec () { print_function "audit_mount_noexec" string="No-exec on /tmp" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_file="/etc/fstab" if [ -e "${check_file}" ]; then verbose_message "Temp File Systems mounted with noexec" "check" if [ "${audit_mode}" != "2" ]; then command="grep -v \"^#\" \"${check_file}\" | grep \"tmpfs\" | grep -v noexec | head -1 | wc -l | sed \"s/ //g\"" command_message "${command}" nodev_check=$( eval "${command}" ) if [ "${nodev_check}" = 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Found tmpfs filesystems that should be mounted noexec" fix_message "cat ${check_file} | awk '( \$3 ~ /^tmpfs$/ ) { \$4 = \$4 \",noexec\" }; { printf \"%-26s %-22s %-8s %-16s %-1s %-1s\n\",\$1,\$2,\$3,\$4,\$5,\$6 }' > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" fi if [ "${audit_mode}" = 0 ]; then set_message "Setting noexec on tmpfs" backup_file "${check_file}" command="awk '( \$3 ~ /^tmpfs$/ ) { \$4 = \$4 \",noexec\" }; { printf \"%-26s %-22s %-8s %-16s %-1s %-1s\\n\",\$1,\$2,\$3,\$4,\$5,\$6 }' < \"${check_file}\" > \"${temp_file}\"" command_message "${command}" eval "${command}" command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "No filesystem that should be mounted with noexec" fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi fi fi check_file_perms "${check_file}" "0644" "root" "root" fi else na_message "${string}" fi } ================================================ FILE: modules/mounts/audit_mount_setuid.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_mount_setuid # # Check Set-UID on mounts # # Refer to Section(s) 1.1.3,13,15 Page(s) 14-25 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.1.3,13,15 Page(s) 17-27 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.1.4,9,16,19 Page(s) 29,34,41,44 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 1.1.4,9,16,19 Page(s) 28,33,40,43 CIS Ubuntu LTS 16.04 Benchmark v1.0.0 # Refer to Section(s) 1.1.2.[1-7].3 Page(s) 82-3,91-2,101-2, # 109-10,116-7,125-6 # 134-5 CIS Ubuntu LTS 24.04 Benchmark v1.0.0 # Refer to Section(s) 2.3,13,15 Page(s) 16-25 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 6.1 Page(s) 21 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 5.2 Page(s) 76-7 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 1.1.4,9,16 Page(s) 28,33,40 CIS Amazon Linux Benchmark v2.0.0 #. audit_mount_setuid () { print_function "audit_mount_setuid" string="Set-UID on Mounted Devices" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file="/etc/rmmount.conf" if [ -f "${check_file}" ]; then command="grep -v \"^#\" \"${check_file}\" | grep \"\\-o nosuid\"" command_message "${command}" nosuid_check=$( eval "${command}" ) log_file="${work_dir}/${check_file}" if [ -n "$nosuid_check" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Set-UID not restricted on user mounted devices" fi if [ "${audit_mode}" = 0 ]; then check_message "Set-UID restricted on user mounted devices" backup_file "${check_file}" check_append_file "${check_file}" "mount * hsfs udfs ufs -o nosuid" "hash" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Set-UID not restricted on user mounted devices" fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi fi fi fi fi if [ "${os_name}" = "Linux" ]; then check_file="/etc/fstab" if [ -e "${check_file}" ]; then verbose_message "File Systems mounted with nodev" "check" if [ "${audit_mode}" != "2" ]; then command="grep -v \"^#\" \"${check_file}\" | grep -E \"ext2|ext3|ext4|swap|tmpfs\" | grep -v '/ ' | grep -cv '/boot' | sed \"s/ //g\"" command_message "${command}" nodev_check=$( eval "${command}" ) if [ ! "$nodev_check" = "0" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Found filesystems that should be mounted nodev" verbose_message "cat ${check_file} | awk '( \$3 ~ /^ext[2,3,4]|tmpfs$/ && \$2 != \"/\" ) { \$4 = \$4 \",nosuid\" }; { printf \"%-26s %-22s %-8s %-16s %-1s %-1s\\n\",\$1,\$2,\$3,\$4,\$5,\$6 }' > ${temp_file}" "fix" verbose_message "cat ${temp_file} > ${check_file}" "fix" verbose_message "rm ${temp_file}" "fix" fi if [ "${audit_mode}" = 0 ]; then verbose_message "Setting nodev on filesystems" "set" backup_file "${check_file}" command="awk '( \$3 ~ /^ext[2,3,4]|tmpfs$/ && \$2 != \"/\" ) { \$4 = \$4 \",nosuid\" }; { printf \"%-26s %-22s %-8s %-16s %-1s %-1s\\n\",\$1,\$2,\$3,\$4,\$5,\$6 }' < \"${check_file}\" > \"${temp_file}\"" command_message "${command}" eval "${command}" command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "No filesystem that should be mounted with nodev" fi if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi fi fi check_file_perms "${check_file}" "0644" "root" "root" fi fi else na_message "${string}" fi } ================================================ FILE: modules/nis/audit_crypt_policy.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_crypt_policy # # Set default cryptographic algorithms #. audit_crypt_policy () { print_function "audit_crypt_policy" string="Cryptographic Algorithms" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/security/policy.conf" "CRYPT_DEFAULT" "eq" "6" "hash" check_file_value "is" "/etc/security/policy.conf" "CRYPT_ALGORITHMS_ALLOW" "eq" "6" "hash" else na_message "${string}" fi } ================================================ FILE: modules/nis/audit_disk_encryption.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_disk_encryption # # Check Disk Encryption is enabled # # Refer to Section(s) 2.6.1 Page(s) 54 CIS Apple OS X 10.12 Benchmark v1.0.0 #. audit_disk_encryption () { print_function "audit_disk_encryption" string="Disk Encryption" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then disk_check=$( diskutil cs list | grep -i encryption | grep AES-XTS ) if [ "${disk_check}" ]; then inc_secure "Disk encryption is enabled" else inc_insecure "Disk encryption is not enabled" fi fi else na_message "${string}" fi } ================================================ FILE: modules/nis/audit_encryption_kit.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_encryption_kit # # Check Encryption Kit # # Refer to Section(s) 1.3 Page(s) 15-6 CIS Solaris 10 Benchmark v5.1.0 #. audit_encryption_kit () { print_function "audit_encryption_kit" string="Encryption Toolkit" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_solaris_package "SUNWcry" check_solaris_package "SUNWcryr" if [ "${os_update}" -le 4 ]; then check_solaris_package "SUNWcryman" fi fi else na_message "${string}" fi } ================================================ FILE: modules/nis/audit_nis_client.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_nis_client # # Check NIS client # # Refer to Section(s) 2.5 Page(s) 18 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 2.2.3 Page(s) 24-5 CIS Solaris 10 Benchmrk v5.1.0 # Refer to Section(s) 2.1.5 Page(s) 58 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.5 Page(s) 53 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.3.1 Page(s) 123 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.1.2 Page(s) 41 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.3.1 Page(s) 110-1 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.3.1 Page(s) 119-20 CIS Ubuntu 16.04 Benchmark v2.0.0 # Refer to Section(s) 2.2.1 Page(s) 292-3 CIS Ubuntu 16.04 Benchmark v2.0.0 #. audit_nis_client () { print_function "audit_nis_client" string="NIS Client Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/nis/client" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then for service_name in ypbind nis; do check_linux_service "${service_name}" "off" check_linux_package "uninstall" "${service_name}" done fi else na_message "${string}" fi } ================================================ FILE: modules/nis/audit_nis_entries.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2154 # audit_nis_entries # # Check NIS entries # # Refer to Section(s) 9.2.2-4 Page(s) 163-5 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.2-4 Page(s) 188-190 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.2-4 Page(s) 166-8 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 13.2-4 Page(s) 154-6 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 9.4 Page(s) 118-9 CIS Solaris 10 Benchmark v1.1.0 #. audit_nis_entries () { print_function "audit_nis_entries" string="NIS Map Entries" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then for check_file in /etc/passwd /etc/shadow /etc/group; do if test -r "${check_file}"; then if [ "${audit_mode}" != 2 ]; then command="grep -c \"^+\" \"${check_file}\" | sed \"s/ //g\"" command_message "${command}" entry_check=$( eval "${command}" ) if [ ! "${entry_check}" = "0" ]; then command="grep \"^+\" \"${check_file}\"" command_message "${command}" file_entries=$( eval "${command}" ) for file_entry in ${file_entries}; do if [ "${audit_mode}" = 1 ]; then inc_insecure "NIS entry \"${file_entry}\" in ${check_file}" fix_message "sed -e \"s/^+/#&/\" < ${check_file} > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "File \"${check_file}\" to have no NIS entries" command="sed -e \"s/^+/#&/\" < \"${check_file}\" > \"${temp_file}\"" command_message "${command}" file_list=$( eval "${command}" ) command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" file_list=$( eval "${command}" ) if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" != "11" ]; then command="pkgchk -f -n -p \"${check_file}\" 2> /dev/null" command_message "${command}" file_list=$( eval "${command}" ) else command="pkg fix $( pkg search \"${check_file}\" | grep pkg | awk '{print \$4}' )" command_message "${command}" file_list=$( eval "${command}" ) fi fi if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi done if [ "${file_entry}" = "" ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "No NIS entries in \"${check_file}\"" fi fi fi else restore_file "${check_file}" "${restore_dir}" fi fi done else na_message "${string}" fi } ================================================ FILE: modules/nis/audit_nis_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_nis_server # # Check NIS daemon settings # # Refer to Section(s) 2.1.7 Page(s) 51-52 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.6 Page(s) 58-9 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.6 Page(s) 53-4 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.16 Page(s) 117 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.1.1 Page(s) 40 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 3.12-3 Page(s) 13-14 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.4 Page(s) 17-8 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 2.2.2 Page(s) 23-4 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 2.2.16 Page(s) 109 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.17 Page(s) 118 CIS Ubuntu 16.04 Benchmark v2.0.0 # Refer to Section(s) 2.1.10 Page(s) 254-6 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_nis_server () { print_function "audit_nis_server" string="NIS Server Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then for service_name in "svc:/network/nis/server" \ "svc:/network/nis/passwd" "svc:/network/nis/update" \ "svc:/network/nis/xfr"; do check_sunos_service "${service_name}" "disabled" done fi if [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/nis/server" "disabled" check_sunos_service "svc:/network/nis/domain" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then for service_name in yppasswdd ypserv ypxfrd; do check_linux_service "${service_name}" "off" check_linux_package "uninstall" "${service_name}" done fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/rc.conf" "nis_server_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "nis_ypxfrd_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "nis_yppasswdd_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "rpc_ypupdated_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "nis_client_enable" "eq" "NO" "hash" check_file_value "is" "/etc/rc.conf" "nis_ypset_enable" "eq" "NO" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/nis/audit_nisplus.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_nisplus # # Check NIS+ daemons # # Refer to Section(s) 2.2.4 Page(s) 25 CIS Solaris 10 Benchmark v5.1.0 #. audit_nisplus () { print_function "audit_nisplus" string="NIS+ Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/network/rpc/nisplus" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/ntp/audit_ntp.sh ================================================ #!/bin/sh # -> Needs fixing # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ntp # # Check NTP settings # # Refer to Section(s) 3.6 Page(s) 62-3 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.6 Page(s) 75-6 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.6 Page(s) 65-6 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.1.1-2 Page(s) 98-101 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 2.4.5.1 Page(s) 35-6 CIS Apple OS X 10.5 Benchmark v1.1.0 # Refer to Section(s) 2.2.1-3 Page(s) 26-31 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.3.2.1-2 Page(s) 82-6 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 # Refer to Section(s) 6.5 Page(s) 55-6 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.9.2 Page(s) 16-7 CIS ESX Server 4 Benchmark v1.1.0 # Refer to Section(s) 2.2.1.1-2 Page(s) 90-2 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.1.1-3 Page(s) 98-101 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.3.1.1-3.3.3 Page(s) 306-26 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_ntp () { print_function "audit_ntp" string="Network Time Protocol" check_message "${string}" ntp_package="chrony" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "VMkernel" ]; then if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/inet/ntp.conf" "server" "space" "pool.ntp.org" "hash" if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/ntp4:default" "enabled" fi fi if [ "${os_name}" = "Darwin" ]; then check_file_value "is" "/private/etc/hostconfig" "TIMESYNC" "eq" "-YES-" "hash" check_launchctl_service "org.ntp.ntpd" "on" #check_file="/private/etc/ntp.conf" if [ "${long_os_version}" -ge 1009 ]; then check_file_value "is" "/etc/ntp-restrict.conf" "restrict" "space" "lo interface ignore wildcard interface listen lo" "hash" check_osx_systemsetup "getusingnetworktime" "on" timeserver="${country_suffix}.pool.ntp.org" check_osx_systemsetup "getnetworktimeserver" "${timeserver}" fi fi if [ "${os_name}" = "VMkernel" ]; then check_linux_service "ntpd" "on" check_append_file "/etc/ntp.conf" "restrict 127.0.0.1" "hash" fi if [ "${os_name}" = "Linux" ]; then check_file="/etc/ntp.conf" log_file="ntp.log" do_chrony=0 if [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "CentOS" ] && [ "${os_version}" -ge 7 ]; then do_chrony=1 fi if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 16 ]; then do_chrony=1 fi if [ "${os_vendor}" = "Amazon" ]; then do_chrony=1 fi if [ "${do_chrony}" -eq 1 ] && [ "${ntp_package}" = "chrony" ]; then old_package="systemd-timesyncd" check_linux_package "uninstall" "${old_package}" check_linux_service "${old_package}" "off" check_linux_package "install" "${ntp_package}" check_linux_service "${ntp_package}" "on" check_file_value "is" "/etc/sysconfig/chronyd" "OPTIONS" "eq" "\"-u chrony\"" "hash" for server_number in $( seq 0 3 ); do ntp_server="${server_number}.${country_suffix}.pool.ntp.org" check_file_value "is" "/etc/chrony/chrony.conf" "pool" "space" "${ntp_server} iburst" "hash" done else if [ "${ntp_package}" = "systemd-timesyncd" ]; then old_package="chrony" check_linux_package "uninstall" "${old_package}" check_linux_service "${old_package}" "off" check_linux_package "install" "${ntp_package}" check_linux_service "${ntp_package}" "on" conf_file="/etc/systemd/timesyncd.conf" ntp_server="0.${country_suffix}.pool.ntp.org" check_file_value "is" "${conf_file}" "NTP" "eq" "${ntp_server}" "hash" ntp_server="1.${country_suffix}.pool.ntp.org" check_file_value "is" "${conf_file}" "FallbackNTP" "eq" "${ntp_server}" "hash" else check_linux_package "install" "ntp" if [ -f "/usr/bin/systemctl" ]; then check_append_file "/usr/lib/systemd/system/ntpd.service" "restrict default kod nomodify nopeer notrap noquery" "hash" check_append_file "/usr/lib/systemd/system/ntpd.service" "restrict -6 default kod nomodify nopeer notrap noquery" "hash" check_file_value "is" "/usr/lib/systemd/system/ntpd.service" "OPTIONS" "eq" "\"-u ntp:ntp -p /var/run/ntpd.pid\"" "hash" check_file_value "is" "/usr/lib/systemd/system/ntpd.service" "ExecStart" "eq" "/usr/sbin/ntpd -u ntp:ntp \$OPTIONS" "hash" else check_linux_service "ntp" "on" fi for server_number in $( seq 0 3 ); do ntp_server="${server_number}.${country_suffix}.pool.ntp.org" check_file_value "is" "/etc/ntp.conf" "server" "space" "${ntp_server}" "hash" done fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/pam/audit_pam_authtok.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2028 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2154 # audit_pam_authtok # # Check PAM use_authok # #. audit_pam_authtok () { print_function "audit_pam_authtok" pam_module="use_authtok" string="PAM ${pam_module} Configuration" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_string="PAM ${pam_module} Configuration" verbose_message "${check_string}" "check" if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 24 ]; then check_dir="/etc/pam.d" if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else pam_check=$( grep -cPH -- "^\h*password\h+([^#\n\r]+)\h+pam_unix\.so\h+([^#\n\r]+\h+)?${pam_module}\b" < "${check_file}" ) if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_pam_authtok_${ansible_counter}" echo "" echo "- name: Checking ${check_string}" echo " command: sh -c \"grep -cPH -- '^\h*password\h+\([^#\n\r]+\)\h+pam_unix\.so\h+\([^#\n\r]+\h+\)?${pam_module}\b' < ${check_file}\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 0" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${check_string}" echo " command: sh -c \"sed \\"s/\(^password.*pam_unix\.so\)\(.*\)/\\1 ${pam_module} \\2/g\\" ${check_file}\"" echo " when: ${ansible_value}.rc == 0 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${pam_check}" = "0" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "PAM ${pam_module} not enabled in \"${check_file}\"" fix_message "sed \"s/\(^password.*pam_unix\.so\)\(.*\)/\1 ${pam_module} \2/g\" < ${check_file} > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" fix_message "PAM ${pam_module} enabled in \"${check_file}\"" sed "s/\(^password.*pam_unix\.so\)\(.*\)/\1 ${pam_module} \2/g" < "${check_file}" > "${temp_file}" cat "${temp_file}" > "${check_file}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else inc_secure "PAM ${pam_module} enabled in \"${check_file}\"" fi fi else na_message "${string}" fi else na_message "${string}" fi } ================================================ FILE: modules/pam/audit_pam_deny.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_pam_deny # # Add pam.deny to pam config files # # Refer to Section(s) 6.7 Page(s) 23 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 6.3.3 Page(s) 162 CIS RHEL 5 Benchmark v2.1.0 #. audit_pam_deny () { print_function "audit_pam_deny" string="PAM Deny Weak Authentication Services" tab=$( printf "\t" ) check_message "${string}" if [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "Linux" ]; then pam_module="pam_deny" if [ "${os_name}" = "FreeBSD" ]; then if [ "${os_version}" -lt 5 ]; then check_append_file "/etc/pam.conf" "rexecd${tab}auth${tab}required${tab}${pam_module}.so" "hash" check_append_file "/etc/pam.conf" "rsh${tab}auth${tab}required${tab}${pam_module}.so" "hash" else : # Need to insert code here # sed -i .preCIS -e 's/nologin/deny/g' /etc/pam.d/rsh /etc/pam.d/rexecd fi fi if [ "${os_name}" = "Linux" ]; then check_append_file "/etc/pam.d/sshd" "auth${tab}requisite${tab}${pam_module}.so" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/pam/audit_pam_gdm_autologin.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_pam_gdm_autologin # # Check PAM GDM autologin settings # # Refer to Section(s) 16.11 Page(s) 54-5 Solaris 11.1 Benchmark v1.0.0 #. audit_pam_gdm_autologin () { print_function "audit_pam_gdm_autologin" string="Gnome Autologin" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "11" ]; then pam_module="gdm-autologin" check_file="/etc/pam.d/${pam_module}" temp_file="${temp_dir}/${pam_module}" if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi if [ "${audit_mode}" != 2 ]; then if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_pam_gdm_autologin_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"cat ${check_file} |grep -v '^#' |grep '^${pam_module}' |head -1 |wc -l\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"sed -i 's/^${pam_module}/#&/g' ${check_file}\"" echo " when: ${ansible_value} .rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi command="grep -v \"^#\" \"${check_file}\" | grep \"^${pam_module}\" | head -1 | wc -l | sed \"s/ //g\"" command_message "${command}" gdm_check=$( eval "${command}" ) if [ "${gdm_check}" != 0 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "${string} is enabled" fix_message "cat ${check_file} |sed 's/^${pam_module}/#&/g' > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" sed "s/^${pam_module}/#&/g" "${check_file}" > "${temp_file}" cat "${temp_file}" > "${check_file}" if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = 1 ];then inc_secure "${string} is disabled" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/pam/audit_pam_rhosts.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2154 # audit_pam_rhosts # # Check PAM rhost settings # # Bug: Need to implement backup_file to after the ansible_mode check # # Refer to Section(s) 6.8 Page(s) 51-52 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.4 Page(s) 89 CIS Solaris 10 Benchmark v5.1.0 #. audit_pam_rhosts () { print_function "audit_pam_rhosts" pam_module="pam_rhosts_auth" string="PAM ${pam_module} Configuration" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then check_file="/etc/pam.conf" if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else if [ -f "${check_file}" ]; then command="grep -v \"^#\" \"${check_file}\" | grep \"${pam_module}\" | head -1 | wc -l | sed \"s/ //g\"" command_message "${command}" pam_check=$( eval "${command}" ) if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_pam_rhosts_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"cat ${check_file} | grep -v '^#' |grep '${pam_module}' |head -1 |wc -l | sed 's/ //g'\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"sed -i 's/^.*${pam_module}/#&/' ${check_file}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${pam_check}" = "1" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Rhost authentication enabled in \"${check_file}\"" fix_message "sed -e 's/^.*${pam_module}/#&/' < ${check_file} > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" else log_file="${work_dir}${check_file}" if [ ! -f "${log_file}" ]; then save_message "File ${check_file} to ${work_dir}${check_file}" command="find \"${check_file}\" | cpio -pdm \"${work_dir}\" 2> /dev/null" command_message "${command}" file_list=$( eval "${command}" ) fi set_message "Rhost authentication to disabled in ${check_file}" command="sed -e 's/^.*${pam_module}/#&/' \"${check_file}\" > \"${temp_file}\"" command_message "${command}" file_list=$( eval "${command}" ) command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" file_list=$( eval "${command}" ) if [ -f "${temp_file}" ]; then rm "${temp_file}" fi if [ "${os_version}" != "11" ]; then command="pkgchk -f -n -p \"${check_file}\" 2> /dev/null" command_message "${command}" file_list=$( eval "${command}" ) else command="pkg fix $( pkg search \"${check_file}\" | grep pkg | awk '{print \$4}' )" command_message "${command}" file_list=$( eval "${command}" ) fi fi else inc_secure "Rhost authentication disabled in \"${check_file}\"" fi fi fi fi if [ "${os_name}" = "Linux" ]; then check_dir="/etc/pam.d" if [ -d "${check_dir}" ]; then command="find \"${check_dir}\" -type f" command_message "${command}" file_list=$( eval "${command}" ) for check_file in ${file_list}; do if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else pam_check=$( grep -v "^#" "${check_file}" | grep -c "rhosts_auth" | sed "s/ //g" ) if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_pam_rhosts_${ansible_counter}" echo "" echo "- name: Checking ${string}" echo " command: sh -c \"cat ${check_file} | grep -v '^#' |grep 'rhosts_auth' |head -1 |wc -l | sed 's/ //g'\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${string}" echo " command: sh -c \"sed -i 's/^.*rhosts_auth/#&/' ${check_file}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${pam_check}" = "1" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Rhost authentication enabled in \"${check_file}\"" fix_message "sed -e 's/^.*rhosts_auth/#&/' < ${check_file} > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "Rhost authentication to disabled in \"${check_file}\"" command="sed -e 's/^.*rhosts_auth/#&/' < \"${check_file}\" > \"${temp_file}\"" command_message "${command}" file_list=$( eval "${command}" ) command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" file_list=$( eval "${command}" ) if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi else inc_secure "Rhost authentication disabled in \"${check_file}\"" fi fi done fi fi else na_message "${string}" fi } ================================================ FILE: modules/pam/audit_rsa_securid_pam.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2028 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_rsa_securid_pam # # Check that RSA is installed #. audit_rsa_securid_pam () { print_function "audit_rsa_securid_pam" string="RSA SecurID PAM Agent Configuration" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then check_file="/etc/sd_pam.conf" if [ -f "${check_file}" ]; then search_string="pam_securid.so" if [ "${os_name}" = "SunOS" ]; then check_file="/etc/pam.conf" if [ -f "${check_file}" ]; then command="grep \"${search_string}\" \"${check_file}\" | awk '{print \$3}'" command_message "${command}" check_value=$( eval "${command}" ) fi fi if [ "${os_name}" = "Linux" ]; then check_file="/etc/pam.d/sudo" if [ -f "${check_file}" ]; then command="grep \"${search_string}\" \"${check_file}\" | awk '{print \$4}'" command_message "${command}" check_value=$( eval "${command}" ) fi fi if [ "${audit_mode}" != 2 ]; then if [ "${check_value}" != "${search_string}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "RSA SecurID PAM Agent is not enabled for sudo" if [ "${os_name}" = "Linux" ]; then fix_message "cat ${check_file} |sed 's/^auth/#\&/' > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "echo \"auth\trequired\tpam_securid.so reserve\" >> ${check_file}" fix_message "rm ${temp_file}" fi if [ "${os_name}" = "SunOS" ]; then fix_message "echo \"sudo\tauth\trequired\tpam_securid.so reserve\" >> ${check_file}" fi fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "Configuring RSA SecurID PAM Agent for sudo" if [ "${os_name}" = "Linux" ]; then command="sed -e 's/^auth/#\\&/' < \"${check_file}\" > \"${temp_file}\"" command_message "${command}" file_list=$( eval "${command}" ) command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" file_list=$( eval "${command}" ) command="echo \"auth\trequired\tpam_securid.so reserve\" >> \"${check_file}\"" command_message "${command}" file_list=$( eval "${command}" ) if [ -f "${temp_file}" ]; then rm "${temp_file}" fi fi if [ "${os_name}" = "SunOS" ]; then echo "sudo\tauth\trequired\tpam_securid.so reserve" >> "${check_file}" fi #echo "Removing: Configuring logrotate" #cat ${check_file} |sed 's,.*{,${search_string} {,' > ${temp_file} #cat ${temp_file} > ${check_file} #rm ${temp_file} fi else if [ "${audit_mode}" = 1 ]; then inc_secure "RSA SecurID PAM Agent is configured for sudo" fi fi else restore_file "${check_file}" "${restore_dir}" fi fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_pass_req.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_pass_req # # Set PASSREQ to YES in /etc/default/login to prevent users from loging on # without a password #. audit_pass_req () { print_function "audit_pass_req" string="Password Required" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/default/login" "PASSREQ" "eq" "YES" "hash" else na_message "${string}" fi } ================================================ FILE: modules/password/audit_passwd_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_passwd_perms # # Refer to Section(s) 9.1.2-9 Page(s) 153-9 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.1.2-9 Page(s) 177-83 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.2-9 Page(s) 157-62 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.1.2-9 Page(s) 261-8 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 12.2-7 Page(s) 146-50 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 6.1.2-9 Page(s) 239-46 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.1 Page(s) 21 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.11.1-3 Page(s) 192-4 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 6.1.2-9 Page(s) 253-60 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 7.1.1-8 Page(s) 934-49 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_passwd_perms () { print_function "audit_passwd_perms" string="Group and Password File Permissions" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then for check_file in /etc/passwd /etc/group; do check_file_perms "${check_file}" "0644" "root" "security" done check_dir="/etc/security" check_file_perms "${check_dir}" "0750" "root" "security" fi if [ "${os_name}" = "Linux" ]; then check_file_perms "/etc/passwd" "0644" "root" "root" check_file_perms "/etc/group" "0644" "root" "root" check_file_perms "/etc/shadow" "0600" "root" "root" check_file_perms "/etc/gshadow" "0600" "root" "root" check_file_perms "/etc/group-" "0600" "root" "root" check_file_perms "/etc/passwd-" "0600" "root" "root" check_file_perms "/etc/shadow-" "0600" "root" "root" check_file_perms "/etc/gshadow-" "0600" "root" "root" fi if [ "${os_name}" = "FreeBSD" ]; then check_file_perms "/etc/passwd" "0644" "root" "${wheel_group}" check_file_perms "/etc/group" "0644" "root" "${wheel_group}" check_file_perms "/etc/pwd.db_file" "0644" "root" "${wheel_group}" check_file_perms "/etc/master.passwd" "0600" "root" "${wheel_group}" check_file_perms "/etc/spwd.db" "0600" "root" "${wheel_group}" fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_password_expiry.sh ================================================ #!/bin/sh # shellcheck disable=SC2034 # shellcheck disable=SC1090 # shellcheck disable=SC2154 # audit_password_expiry # # Refer to Section(s) 7.1.1-3 Page(s) 143-146 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 7.1.1-3 Page(s) 166-8 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 7.1.1-3 Page(s) 147-9 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.4.1.1-4 Page(s) 245-51 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 10.1.1-3 Page(s) 136-8 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 8.3 Page(s) 27 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.1.1-11 Page(s) 17-26 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 7.1 Page(s) 61-62 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 7.2 Page(s) 101-3 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 5.4.1.1-4 Page(s) 226-30 CIS Amazon Linux v2.0.0 # Refer to Section(s) 5.4.1.1-4 Page(s) 238-43 CIS Ubuntu 16.04 v1.0.0 # Refer to Section(s) 5.4.1.1-3 Page(s) 677-85 CIS Ubuntu 24.04 v1.0.0 #. audit_password_expiry () { print_function "audit_password_expiry" string="Password Expiration Parameters on Active Accounts" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_chsec "/etc/security/user" "default" "mindiff" "4" check_chsec "/etc/security/user" "default" "minage" "1" check_chsec "/etc/security/user" "default" "maxage" "13" check_chsec "/etc/security/user" "default" "minlen" "8" check_chsec "/etc/security/user" "default" "minalpha" "2" check_chsec "/etc/security/user" "default" "minother" "2" check_chsec "/etc/security/user" "default" "maxrepeats" "2" check_chsec "/etc/security/user" "default" "histexpire" "13" check_chsec "/etc/security/user" "default" "histsize" "20" check_chsec "/etc/security/user" "default" "maxexpired" "2" if [ "${os_version}" -gt 4 ]; then if [ "${os_version}" = "5" ]; then if [ "${os_update}" -gt 3 ]; then check_chsec "/etc/security/login.cfg" "usw" "pwd_algorithm" "ssha256" fi else check_chsec "/etc/security/login.cfg" "usw" "pwd_algorithm" "ssha256" fi fi fi if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/default/passwd" "MAXWEEKS" "eq" "13" "hash" check_file_value "is" "/etc/default/passwd" "MINWEEKS" "eq" "1" "hash" check_file_value "is" "/etc/default/passwd" "WARNWEEKS" "eq" "4" "hash" check_file_value "is" "/etc/default/login" "DISABLETIME" "eq" "3600" "hash" fi if [ "${os_name}" = "Linux" ]; then check_file_value "is" "/etc/login.defs" "PASS_MAX_DAYS" "eq" "90" "hash" check_file_value "is" "/etc/login.defs" "PASS_MIN_DAYS" "eq" "7" "hash" check_file_value "is" "/etc/login.defs" "PASS_WARN_AGE" "eq" "14" "hash" check_file_value "is" "/etc/login.defs" "PASS_MIN_LEN" "eq" "9" "hash" check_file_perms "/etc/login.defs" "0640" "root" "root" fi if [ "${os_name}" = "FreeBSD" ]; then if [ "${os_version}" -gt 5 ]; then check_file_value "is" "/etc/adduser.conf" "passwdtype" "eq" "yes" "hash" check_file_value "is" "/etc/adduser.conf" "upwexpire" "eq" "91d" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_password_fields.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_password_fields # # Ensure Password Fields are Not Empty # Verify System Account Default Passwords # Ensure Password Fields are Not Empty # # Refer to Section(s) 9.2.1 Page(s) 162-3 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.1 Page(s) 187-8 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.1 Page(s) 166 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.2.1 Page(s) 274 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 13.1 Page(s) 154 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 8.2 Page(s) 27 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.2.15 Page(s) 219 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9.4 Page(s) 75 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.3 Page(s) 118 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.1 Page(s) 252 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.1-4 Page(s) 266-9 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 5.4.2.1,7.2.1-2 Page(s) 695-7,965-9 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_password_fields () { print_function "audit_password_fields" string="Password Fields" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${audit_mode}" != 2 ]; then check_file="/etc/passwd" command="awk -F: '(\$3 == 0) { print \$1 }' \"${check_file}\" | grep -v root" command_message "${command}" user_list=$( eval "${command}" ) if [ "$user_list" = "" ]; then inc_secure "No non root users have UID 0" else for user_name in ${user_list}; do if [ "${user_name}" != "root" ]; then inc_insecure "Non root user ${user_name} has UID 0" fi done fi else check_file="/etc/passwd" restore_file "${check_file}" "${restore_dir}" fi verbose_message "Shadow Fields" "check" if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${audit_mode}" != 2 ]; then check_file="/etc/shadow" empty_count=0 if [ "${os_name}" = "AIX" ]; then command="pwdck –n ALL" command_message "${command}" user_list=$( eval "${command}" ) else command="awk -F':' '{ print \$1\":\"\$2\":\" }' < /etc/shadow | grep \"::$\" | cut -f1 -d:" command_message "${command}" user_list=$( eval "${command}" ) fi for user_name in ${user_list}; do empty_count=1 if [ "${audit_mode}" = 1 ]; then inc_insecure "No password field for \"${user_name}\" in \"${check_file}\"" fix_message "passwd -d ${user_name}" if [ "${os_name}" = "SunOS" ]; then fix_message "passwd -N ${user_name}" fi fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" set_message "No password for \"${user_name}\"" passwd -d "${user_name}" if [ "${os_name}" = "SunOS" ]; then passwd -N "${user_name}" fi fi done if [ "$empty_count" = 0 ]; then inc_secure "No empty password entries" fi for check_file in /etc/passwd /etc/shadow; do if test -r "${check_file}"; then command="grep '^+:' ${check_file} | head -1 | wc -l | sed \"s/ //g\"" command_message "${command}" legacy_check=$( eval "${command}" ) if [ "${legacy_check}" != "0" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Legacy field found in \"${check_file}\"" fix_message "grep -v '^+:' : ${check_file} > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" remove_message "Legacy entries from \"${check_file}\"" command="grep -v \"^+:\" \"${check_file}\" > \"${temp_file}\"" command_message "${command}" eval "${command}" command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" fi else inc_secure "No legacy entries in \"${check_file}\"" fi fi done else check_file="/etc/shadow" restore_file "${check_file}" "${restore_dir}" fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_password_hashing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_password_hashing # # Check that password hashing is set to SHA512. # # Refer to Section(s) 6.3.1 Page(s) 138-9 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.3.4 Page(s) 162-3 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 6.3.1 Page(s) 141-2 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.3.4 Page(s) 234-5 CIS RHEL 7 Benchmark v1.2.0 # Refer to Section(s) 5.3.4 Page(s) 224-5 CIS Amazon Linux Benchmark v1.2.0 # Refer to Section(s) 5.4.1.4 Page(s) 666-8 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_password_hashing () { print_function "audit_password_hashing" string="Password Hashing" check_message "${string}" if [ "${os_name}" = "Linux" ]; then hashing="${1}" if [ "${1}" = "" ]; then hashing="sha512" fi if [ "${os_name}" = "Linux" ]; then if [ -f "/usr/sbin/authconfig" ]; then verbose_message "Password Hashing" "check" if [ "${audit_mode}" != 2 ]; then log_file="hashing.log" check_value=$( authconfig --test | grep hashing | awk '{print $5}' ) if [ "${check_value}" != "${hashing}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Password hashing not set to \"${hashing}\"" fix_message "authconfig --passalgo=${hashing}" fi if [ "${audit_mode}" = 0 ]; then set_message "Password hashing to \"${hashing}\"" log_file="${work_dir}/${log_file}" echo "${check_value}" > "${log_file}" eval "authconfig --passalgo=${hashing}" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Password hashing set to \"${hashing}\"" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then check_value=$( cat "${restore_file}" ) restore_message "Password hashing to \"${check_value}\"" eval "authconfig --passalgo=${check_value}" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_password_hints.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_password_hints # # Password hints make it easier for unauthorized persons to gain access to systems by # displaying information provided by the user to assist in remembering the password. This # info could include the password itself or other information that might be readily # discerned with basic knowledge of the end user. # # Refer to Section 6.1.2 Page(s) 73-4 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section 6.1.2 Page(s) 154-5 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section 2.10.5 Page(s) 231-3 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_login_details () { print_function "audit_login_details" string="Login display details" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_int "/Library/Preferences/com.apple.loginwindow" "RetriesUntilHint" "0" else na_message "${string}" fi } ================================================ FILE: modules/password/audit_password_history.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_password_history # # Refer to Section(s) 5.4.1.6 Page(s) 692-3 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_password_history () { print_function "audit_password_history" string="Password History" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${audit_mode}" != 2 ]; then check_file="/etc/shadow" current_date=$( date +%s ) command="awk -F: '\$2~/^\$.+\$/{print \$1}' \"${check_file}\"" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do command="date -d \"\$(chage --list \"${user_name}\" | grep '^Last password change' | cut -d: -f2 | grep -v 'never\$')\" +%s" command_message "${command}" change_date=$( eval "${command}" ) if [ "${change_date}" -gt "${current_date}" ]; then inc_insecure "User ${user_name} has a last password change date in the future" else inc_secure "User ${user_name} has a last password change date in the past" fi done else for check_file in /etc/passwd /etc/shadow; do restore_file "${check_file}" "${restore_dir}" done fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_password_lock.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_password_lock # # Refer to Section(s) 5.4.1.5 Page(s) 689-91 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_password_lock () { print_function "audit_password_lock" string="Inactive Password Lock" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${audit_mode}" != 2 ]; then check_file="/etc/shadow" inactive_time="45" command="useradd -D | grep INACTIVE | cut -f2 -d=" command_message "${command}" inactive_test=$( eval "${command}" ) if [ "${inactive_test}" -lt "${inactive_time}" ]; then inc_insecure "Inactive password lock is less than ${inactive_time}" else inc_secure "Inactive password lock is equal to or greater than ${inactive_time}" fi user_list=$( awk -F: '($2~/^\$.+\$/) {if($7 > $inactive || $7 < 0)print $1 }' "${check_file}" ) if [ "${user_list}" = "" ]; then inc_secure "No users with inactive password locks less that ${inactive_time}" else for user_name in ${user_list}; do inc_insecure "User ${user_name} has an inactive password lock less than ${inactive_time}" done fi else for check_file in /etc/passwd /etc/shadow; do restore_file "${check_file}" "${restore_dir}" done fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_password_strength.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_password_strength # # Refer to Section(s) 5.12-19 Page(s) 58-66 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 5.2.1-6 Page(s) 112-27 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 8.10 Page(s) CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 7.2 Page(s) 63-4 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 7.3 Page(s) 103-4 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 5.2.1-8 Page(s) 315-30 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_password_strength () { print_function "audit_password_strength" string="Strong Password Creation Policies" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/default/passwd" "PASSLENGTH" "eq" "8" "hash" check_file_value "is" "/etc/default/passwd" "NAMECHECK" "eq" "YES" "hash" check_file_value "is" "/etc/default/passwd" "HISTORY" "eq" "10" "hash" check_file_value "is" "/etc/default/passwd" "MINDIFF" "eq" "3" "hash" check_file_value "is" "/etc/default/passwd" "MINALPHA" "eq" "2" "hash" check_file_value "is" "/etc/default/passwd" "MINUPPER" "eq" "1" "hash" check_file_value "is" "/etc/default/passwd" "MINLOWER" "eq" "1" "hash" check_file_value "is" "/etc/default/passwd" "MINDIGIT" "eq" "1" "hash" check_file_value "is" "/etc/default/passwd" "MINNONALPHA" "eq" "1" "hash" check_file_value "is" "/etc/default/passwd" "MAXREPEATS" "eq" "0" "hash" check_file_value "is" "/etc/default/passwd" "WHITESPACE" "eq" "YES" "hash" check_file_value "is" "/etc/default/passwd" "DICTIONDBDIR" "eq" "/var/passwd" "hash" check_file_value "is" "/etc/default/passwd" "DICTIONLIST" "eq" "/usr/share/lib/dict/words" "hash" fi if [ "${os_name}" = "Darwin" ]; then check_pwpolicy "requiresAlpha" "1" # check_pwpolicy "minimumAlphaCharacters" "1" check_pwpolicy "requiresSymbol" "1" # check_pwpolicy "minimumSymbolCharacters" "1" check_pwpolicy "RequiresNumeric" "1" # check_pwpolicy "minimumNumericCharacters" "1" if [ "${long_os_version}" -ge 1014 ]; then check_pwpolicy "requiresMixedCase" "1" check_pwpolicy "usingHistory" "15" fi check_pwpolicy "maxMinutesUntilChangePassword" "86400" check_pwpolicy "minChars" "15" check_pwpolicy "passwordCannotBeName" "1" check_pwpolicy "minutesUntilFailedLoginReset" "0" check_pwpolicy "policyAttributeMaximumFailedAuthentications" "15" fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/login.conf" "passwd_format" "eq" "blf" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_shadow_group.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_shadow_group # # Check shadow group # # Refer to Section(s) 13.20 Page(s) 168-9 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 6.2.20 Page(s) 287 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 7.2.4 Page(s) 972-3 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_shadow_group () { print_function "audit_shadow_group" string="Shadow Group" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_file="/etc/group" temp_file="${temp_dir}/group" if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" fi if [ "${audit_mode}" != 2 ]; then shadow_check=$( grep -v "^#" "${check_file}" | grep ^shadow | cut -f4 -d:| wc -c | sed "s/ //g" ) if [ "$shadow_check" != 0 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Shadow group contains members" fix_message "cat ${check_file} |awk -F':' '( \$1 == \"shadow\" ) {print \$1\":\"\$2\":\"\$3\":\" ; next}; {print}' > ${temp_file}" fix_message "cat ${temp_file} > ${check_file}" fix_message "rm ${temp_file}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" command="awk -F':' '( \$1 == \"shadow\" ) {print \$1\":\"\${2}\":\"\${3}\":\" ; next}; {print}' < \"${check_file}\" > \"${temp_file}\"" command_message "${command}" eval "${command}" command="cat \"${temp_file}\" > \"${check_file}\"" command_message "${command}" eval "${command}" command="rm \"${temp_file}\"" command_message "${command}" eval "${command}" fi else if [ "${audit_mode}" = 1 ];then inc_secure "No members in shadow group" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_smbpasswd_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_smbpasswd_perms # # Check SMB Password sttings # # Refer to Section(s) 11.4-5 Page(s) 144-5 CIS Solaris 10 Benchmark v1.1.0 #. audit_smbpasswd_perms () { print_function "audit_smbpasswd_perms" string="SMB Password File" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_perms "/etc/sfw/private/smbpasswd" "0600" "root" "root" else na_message "${string}" fi } ================================================ FILE: modules/password/audit_system_auth_password_hashing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth_password_hashing # # heck password hashing settings # # Refer to Section(s) 5.3.4 Page(s) 243 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.3.4 Page(s) 224 CIS Amazon Linux Benchmark v2.0.0 #. audit_system_auth_password_hashing () { print_function "audit_system_auth_password_hashing" auth_string="${1}" search_string="${2}" temp_file="${temp_dir}/audit_system_auth_password_hashing" check_file="/etc/pam.d/common-password" string="Password minimum strength enabled in \"${check_file}\"" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then if [ -f "${check_file}" ]; then command="grep \"^${auth_string}\" \"${check_file}\" | grep \"${search_string}$\" | awk '{print \$8}'" command_message "${command}" check_value=$( eval "${command}" ) lock_command="sed 's/^password\ssufficient\spam_unix.so/password sufficient pam_unix.so sha512/g' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${check_value}" != "${search_string}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Password strength settings not enabled in ${check_file}" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Password minimum length in \"${check_file}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Password strength settings enabled in \"${check_file}\"" fi fi fi else restore_file="/etc/pam.d/common-password" restore_file "${restore_file}" "${restore_dir}" fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_system_auth_password_history.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth_password_history # # Check password history settings # # Refer to Section(s) 6.3.4 Page(s) 141-2 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.3.4 Page(s) 144-5 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.3.3 Page(s) 242 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.3.3 Page(s) 233 CIS Amazon Linux Benchmark v1.2.0 # Refer to Section(s) 9.3.3 Page(s) 134 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 7.1.10 Page(s) 952-3 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_system_auth_password_history () { print_function "audit_system_auth_password_history" auth_string="${1}" search_string="${2}" search_value="${3}" temp_file="${temp_dir}/audit_system_auth_password_history" check_file="/etc/security/opasswd" string="Password entry \"${search_string}\" set to \"${search_value}\" in \"${check_file}\"" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_file_exists "${check_file}" "yes" for check_file in /etc/security/opasswd /etc/security/opasswd.old; do check_file_perms "${check_file}" "0600" "root" "root" done for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do if [ -f "${check_file}" ]; then if [ "${audit_mode}" != 2 ]; then verbose_message "Password entry \"${search_string}\" set to \"${search_value}\" in \"${check_file}\"" "check" command="grep \"^${auth_string}\" \"${check_file}\" | grep \"${search_string}$\" | awk -F \"${search_string}=\" '{print \$2}' | awk '{print \$1}'" command_message "${command}" check_value=$( eval "${command}" ) lock_command="awk '( \$1 == \"password\" && \$3 == \"pam_unix.so\" ) { print \$0 \" ${search_string}=${search_value}\"; next };' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${check_value}" != "${search_value}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Password entry \"${search_string}\" is not set to \"${search_value}\" in \"${check_file}\"" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" fix_message "Password entry in \"${check_file}\"" run_lockdown "${lock_command}" "Password entry in ${check_file}" "sudo" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Password entry \"${search_string}\" set to \"${search_value}\" in \"${check_file}\"" fi fi else for restore_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do restore_file "${restore_file}" "${restore_dir}" done fi fi done else na_message "${string}" fi } ================================================ FILE: modules/password/audit_system_auth_password_policy.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth_password_policy # # Check password policy settings # # Refer to Section(s) 6.3.2 Page(s) 139-140 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.3.2 Page(s) 142-3 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 9.3.1 Page(s) 132-3 CIS SLES 11 Benchmark v1.0.0 #. audit_system_auth_password_policy () { print_function "audit_system_auth_password_policy" auth_string="${1}" search_string="${2}" search_value="${3}" temp_file="${temp_dir}/audit_system_auth_password_policy" string="Password policy" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do if [ -f "${check_file}" ]; then verbose_message "Password \"${search_string}\" is set to \"${search_value}\" in \"${check_file}\"" "check" command="grep \"^${auth_string}\" \"${check_file}\" | grep \"${search_string}$\" | awk -F \"${search_string}=\" '{print \$2}' | awk '{print \$1}'" command_message "${command}" check_value=$( eval "${command}" ) lock_command="awk '( \$1 == \"password\" && \$2 == \"requisite\" && \$3 == \"pam_cracklib.so\" ) { print \$0 \" dcredit=-1 lcredit=-1 ocredit=-1 ucredit=-1 minlen=9\"; next }; { print }' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${check_value}" != "${search_value}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Password \"${search_string}\" is not set to \"${search_value}\" in \"${check_file}\"" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Password \"${search_string}\" to \"${search_value}\" in \"${check_file}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Password \"${search_string}\" set to \"${search_value}\" in \"${check_file}\"" fi fi fi done else for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do restore_file "${check_file}" "${restore_dir}" done fi else na_message "${string}" fi } ================================================ FILE: modules/password/audit_system_auth_password_strength.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_system_auth_password_strength # # Check password minimum strength enabled #. audit_system_auth_password_strength () { print_function "audit_system_auth_password_strength" auth_string="${1}" search_string="${2}" temo_file="${temp_dir}/audit_system_auth_password_strength" string="Password minimum strength" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do if [ -f "${check_file}" ]; then verbose_message "Password minimum strength enabled in \"${check_file}\"" "check" command="grep \"^${auth_string}\" \"${check_file}\" | grep \"${search_string}$\" | awk '{print \$8}'" command_message "${command}" check_value=$( eval "${command}" ) lock_command="sed 's/^password.*pam_deny.so$/&\npassword\t\trequisite\t\t\tpam_passwdqc.so min=disabled,disabled,16,12,8/' < ${check_file} > ${temo_file} ; cat ${temp_file} > ${check_file} ; rm ${temp_file}" if [ "${check_value}" != "${search_string}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Password strength settings not enabled in \"${check_file}\"" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Password minimum length in \"${check_file}\"" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Password strength settings enabled in \"${check_file}\"" fi fi fi done else for check_file in /etc/pam.d/common-auth /etc/pam.d/system-auth; do restore_file "${check_file}" "${restore_dir}" done fi else na_message "${string}" fi } ================================================ FILE: modules/power/audit_power_management.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_power_management # # Refer to Section(s) 2.12.5 Page(s) 209-210 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 10.1 Page(s) 91-2 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 10.3 Page(s) 139 CIS Solaris 10 Benchmark v1.1.0 #. audit_power_management () { print_function "audit_power_management" string="Power Management" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_itab "pmd" "off" fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file_value "is" "/etc/default/power" "PMCHANGEPERM" "eq" "-" "hash" check_file_value "is" "/etc/default/power" "CPRCHANGEPERM" "eq" "-" "hash" fi if [ "${os_version}" = "11" ]; then command="poweradm list | grep suspend | awk '{print \$2}' | cut -f2 -d\"=\"" command_message "${command}" poweradm_test=$( eval "${command}" ) log_file="poweradm.log" if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/#log_file" if [ -f "${log_file}" ]; then restore_value=$( cat "${restore_file}" ) if [ "${poweradm_test}" != "${restore_value}" ]; then restore_message "Power suspend to \"${restore_value}\"" eval "poweradm set suspend-enable=${restore_value}" eval "poweradm update" fi fi fi if [ "${poweradm_test}" != "false" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Power suspend enabled" fix_message "poweradm set suspend-enable=false" fix_message "poweradm update" fi if [ "${audit_mode}" = 0 ]; then backup_file="${work_dir}/${log_file}" set_message "Power suspend to disabled" echo "${poweradm_test}" > "${backup_file}" eval "poweradm set suspend-enable=false" eval "poweradm update" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Power suspend disabled" fi fi fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "apmd" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/print/audit_cups.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cups # # Check CUPS # # Refer to Section(s) 3.4 Page(s) 61 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.4 Page(s) 73-4 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.4 Page(s) 64 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.4 Page(s) 104 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.3 Page(s) 53-4 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.2.4 Page(s) 96 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.3 Page(s) 104 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.11 Page(s) 257-9 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_cups () { print_function "audit_cups" string="Printing Services" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for service_name in cups cups-lpd cupsrenice; do check_linux_service "${service_name}" "off" done check_file_perms "/etc/init.d/cups" "0744" "root" "root" check_file_perms "/etc/cups/client.conf" "0644" "root" "lp" check_file_perms "/etc/cups/cupsd.conf" "0600" "lp" "sys" check_file_value "is" "/etc/cups/cupsd.conf" "User" "space" "lp" "hash" check_file_value "is" "/etc/cups/cupsd.conf" "Group" "space" "sys" "hash" else na_message "${string}" fi } ================================================ FILE: modules/print/audit_ppd_cache.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ppd_cache # # Cache for Printer Descriptions. Not required unless using print services. #. audit_ppd_cache () { print_function "audit_ppd_cache" string="PPD Cache" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/application/print/ppd-cache-update:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/print/audit_print.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_print # # Refer to Section(s) 3.14 Page(s) 14-15 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.3.1-2 Page(s) 34-36 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 2.1.7 Page(s) 22 CIS Solaris 10 Benchmark v5.1.0 #. audit_print () { print_function "audit_print" string="Printing Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_itab "qdaemon" "off" check_itab "lpd" "off" check_itab "piobe" "off" fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/application/print/ipp-listener:default" "disabled" check_sunos_service "svc:/application/print/rfc1179" "disabled" check_sunos_service "svc:/application/print/server:default" "disabled" fi fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/rc.conf" "lpd_enable" "eq" "NO" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/print/audit_printer_sharing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_printer_sharing # # Refer to Section(s) 2.2.4 Page(s) 19-20 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.2.4 Page(s) 41 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 2.3.3.4 Page(s) 98-9 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 # Refer to http://support.apple.com/kb/PH11450 # # Printer sharing can be disabled via: cupsctl --no-share-printers # Need to update this code #. audit_printer_sharing () { print_function "audit_printer_sharing" string="Printer Sharing" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then if [ "${long_os_version}" -ge 1014 ]; then command="/usr/bin/sudo /usr/sbin/cupsctl | grep -c \"_share_printers=0\"" command_message "${command}" printer_test=$( eval "${command}" ) else command="system_profiler SPPrintersDataType | grep Shared | awk '{print \$2}' | grep -c 'Yes' | sed \"s/ //g\"" command_message "${command}" printer_test=$( eval "${command}" ) fi if [ "${printer_test}" = "0" ]; then inc_insecure "Printer sharing is enabled" fix_message "Open System Preferences" fix_message "Select Sharing" fix_message "Uncheck Printer Sharing" else inc_secure "Printer Sharing is disabled" fi else fix_message "Open System Preferences" fix_message "Select Sharing" fix_message "Uncheck Printer Sharing" fi else na_message "${string}" fi } ================================================ FILE: modules/remote/audit_remote_consoles.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_remote_consoles # # Check remote consoles # # Refer to Section(s) 9.1 Page(s) 72 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.1 Page(s) 116 CIS Solaris 10 Benchmark v5.1.0 #. audit_remote_consoles () { print_function "audit_remote_consoles" string="Remote Consoles" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi log_file="remoteconsoles.log" if [ "${audit_mode}" != 2 ]; then disable_ttys=0 log_file="${work_dir}/${log_file}" command="/usr/sbin/consadm -p" command_message "${command}" console_list=$( eval "${command}" ) for console_device in $console_list; do disable_ttys=1 if [ "${audit_mode}" = 1 ]; then inc_insecure "Console enabled on \"${console_device}\"" fix_message "consadm -d ${console_device}" fi if [ "${audit_mode}" = 0 ]; then echo "${console_device}" >> "${log_file}" set_message "Console disabled on \"${console_device}\"" command="consadm -d \"${console_device}\"" command_message "${command}" eval "${command}" fi done if [ "${disable_ttys}" = 0 ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "No remote consoles enabled" fi fi else restore_file="${restore_dir}${log_file}" if [ -f "${restore_file}" ]; then command="cat \"${restore_file}\"" command_message "${command}" restore_list=$( eval "${command}" ) for console_device in ${restore_list}; do restore_message "Console to enabled on \"${console_device}\"" command="consadm -a \"${console_device}\"" command_message "${command}" eval "${command}" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/remote/audit_remote_info.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_remote_info # # Turn off remote info services like rstat and finger # # Refer to Section(s) 1.3.16 Page(s) 52-3 CIS AIX Benchmark v1.1.0 #. audit_remote_info () { print_function "audit_remote_info" string="Remote Information Services" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_rctcp "rwhod" "off" fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/rpc/rstat:default" "disabled" check_sunos_service "svc:/network/nfs/rquota:default" "disabled" check_sunos_service "svc:/network/rpc/rusers:default" "disabled" check_sunos_service "svc:/network/finger:default" "disabled" check_sunos_service "svc:/network/rpc/wall:default" "disabled" fi fi else na_message "${string}" fi } ================================================ FILE: modules/remote/audit_remote_management.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_remote_management # # Check remote management # # Refer to Section(s) 2.2.9 Page(s) 25-6 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 2.2.9 Page(s) 48-9 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(S) 2.3.3.6 Page(s) 104-5 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_remote_management () { print_function "audit_remote_management" string="Remote Management" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then command="launchctl list |awk '{print \$3}' |grep -c ARDAgent |sed \"s/ //g\"" command_message "${command}" actual_value=$( eval "${command}" ) if [ "${actual_value}" = "1" ]; then inc_insecure "Remote Management is enabled" fix_message "Open System Preferences" fix_message "Select Sharing" fix_message "Uncheck Remote Management" else inc_secure "Remote Management is disabled" fi else fix_message "Open System Preferences" fix_message "Select Sharing" fix_message "Uncheck Remote Management" fi else na_message "${string}" fi } ================================================ FILE: modules/remote/audit_remote_shell.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_remote_shell # # Turn off remote shell services # # Refer to Section(s) 1.2.7,9 Page(s) 31,33 CIS AIX Benchmark v1.1.0 #. audit_remote_shell () { print_function "audit_remote_shell" string="Remote Shell" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "AIX" ]; then check_chsec "/etc/security/user" "root" "rlogin" "false" for user_name in daemon bin sys adm uucp nobody lpd; do check_chuser "login" "false" "rlogin" "false" "${user_name}" done fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then for service_name in "svc:/network/shell:kshell" \ "svc:/network/login:eklogin" "svc:/network/login:klogin" \ "svc:/network/rpc/rex:default" "svc:/network/rexec:default" \ "svc:/network/shell:default" "svc:/network/login:rlogin" \ "svc:/network/telnet:default"; do check_sunos_service "${service_name}" "disabled" done fi fi if [ "${os_name}" = "Linux" ]; then for service_name in telnet login rlogin rsh shell; do check_linux_service "${service_name}" "off" done fi else na_message "${string}" fi } ================================================ FILE: modules/remote/audit_vnc.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_vnc # # Turn off VNC #. audit_vnc () { print_function "audit_vnc" string="VNC Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/application/x11/xvnc-inetd:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "vncserver" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/rpc/audit_nobody_rpc.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_nobody_rpc # # Check Nobody Access for RPC Encryption Key Storage Service # # Refer to Section(s) 6.2 Page(s) 47 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.3 Page(s) 88 CIS Solaris 10 Benchmark v5.1.0 #. audit_nobody_rpc () { print_function "audit_nobody_rpc" string="Nobody Access for RPC Encryption Key Storage Service" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_file_value "is" "/etc/default/keyserv" "ENABLE_NOBODY_KEYS" "eq" "NO" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/rpc/audit_rpc_bind.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_rpc_bind # # Check that rpc bind has tcp wrappers enabled in case it's turned on. # # Refer to Section(s) 2.2.14 Page(s) 34-5 CIS Solaris 10 Benchmark v5.1.0 #. audit_rpc_bind () { print_function "audit_rpc_bind" string="RPC Bind" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then audit_svccfg_value "svc:/network/rpc/bind" "config/enable_tcpwrappers" "true" fi if [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/rpc/bind" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/rsh/audit_rsh_client.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_rsh_client # # Check RSH client # # Refer to Section(s) 2.1.4 Page(s) 49 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.4 Page(s) 57 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.4 Page(s) 52-3 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.3.2 Page(s) 125 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.1.4 Page(s) 42-3 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.3.2 Page(s) 112 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.3.2 Page(s) 121 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.2.2 Page(s) 294-5 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_rsh_client () { print_function "audit_rsh_client" string="RSH Client" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_linux_package "uninstall" "rsh" check_linux_package "uninstall" "rsh-client" else na_message "${string}" fi } ================================================ FILE: modules/rsh/audit_rsh_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_rsh_server # # check RSH server # # Refer to Section(s) 2.1.3 Page(s) 48 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.3 Page(s) 56-7 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.3 Page(s) 51-2 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.17 Page(s) 118 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.1.3 Page(s) 41-2 CIS SLES 11 Benchmark v1.0.0 #. audit_rsh_server () { print_function "audit_rsh_server" string="RSH Server Daemon" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "Amazon" ]; then for service_name in rsh.socket rlogin.socket rexec.socket; do check_linux_service "${service_name}" "off" done check_linux_package "uninstall" "rsh-server" fi else na_message "${string}" fi } ================================================ FILE: modules/security/audit_secure_empty_trash.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_secure_empty_trash # # Check secure empty trash settings # # Refer to Section(s) 2.8 Page(s) 33 CIS Apple OS X 10.8 Benchmark v1.0.0 #. audit_secure_empty_trash () { print_function "audit_secure_empty_trash" string="Secure Empty Trash" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_int "com.apple.finder" "EmptyTrashSecurely" "1" else na_message "${string}" fi } ================================================ FILE: modules/security/audit_secure_keyboard_entry.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_secure_keyboard_entry # # Check secure keyboard entry settings # # Refer to Section(s) 2.8 Page(s) 33 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(S) 2.10 Page(s) 81 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 6.4.1 Page(s) 413-6 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_secure_keyboard_entry () { print_function "audit_secure_keyboard_entry" string="Secure Keyboard Entry" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_int "Terminal" "SecureKeyboardEntry" "1" "int" else na_message "${string}" fi } ================================================ FILE: modules/security/audit_secure_swap.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_secure_swap # # Check secure swap settings # # Refer to Section(s) 1.4.13.6 Page(s) 47-8 CIS Apple OS X 10.6 Benchmark v1.0.0 #. audit_secure_swap () { print_function "audit_secure_swap" string="Secure Swap" check_message "${string}" if [ "${os_name}" = "Darwin" ]; then check_osx_defaults_bool "/Library/Preferences/com.apple.virtualMemory" "UseEncryptedSwap" "yes" else na_message "${string}" fi } ================================================ FILE: modules/services/audit_inetd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_inetd # # Check inetd # # Refer to Section(s) 10.6 Page(s) 141-2 CIS Solaris 10 Benchmark v1.1.0 #. audit_inetd () { print_function "audit_inetd" string="Inetd" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/inetd:default" "disabled" fi else na_message "Inetd" fi } ================================================ FILE: modules/services/audit_ipmi.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ipmi # # Turn off ipmi environment daemon #. audit_ipmi () { print_function "audit_ipmi" string="IPMI" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/ipmievd:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "ipmi" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/services/audit_ipv6.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ipv6 # # Check IPv6 # # Refer to Section(s) 1.3.11,22-3 Page(s) 47,60-2 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 4.4.2 Page(s) 94 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 4.4.2 Page(s) 85-6 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 7.3.3 Page(s) 76 CIS SLES 11 Benchmark v1.0.0 #. audit_ipv6 () { print_function "audit_ipv6" string="IPv6" check_message "${string}" if [ "$ipv6_disable" = "yes" ]; then if [ "${os_name}" = "AIX" ]; then for service_name in autoconf6 ndpd-host ndpd-router; do check_rctcp "${service_name}" "off" done fi if [ "${os_name}" = "Linux" ]; then if [ "$disable_ipv6" = "yes" ]; then check_append_file "/etc/modprobe.conf" "options ipv6 \"disable=1\"" "hash" if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ]; then check_file_value "is" "/etc/sysconfig/network" "NETWORKING_IPV6" "eq" "no" "hash" check_file_value "is" "/etc/sysconfig/network" "IPV6INIT" "eq" "no" "hash" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/services/audit_iscsi.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_iscsi # # Turn off iscsi target #. audit_iscsi () { print_function "audit_iscsi" string="iSCSI Target Service" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/system/iscsitgt:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "iscsi" "off" check_linux_service "iscsid" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/services/audit_legacy.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_legacy # # Check legacy services # # Refer to Section(s) 2.1-8 Page(s) 4-8 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.3.17,24-52 Page(s) 54-5,63-96 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 4.5 Page(s) 38-9 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.1.1-10 Page(s) 88-97 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 5.2-11 Page(s) 46-51 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 2.1.1-9 Page(s) 79-87 CIS Amazon Linux Benchmark v2.0.0 #. audit_legacy_inet () { print_function "audit_legacy_inet" string="Inet Services" check_message "${string}" for service_name in time echo discard daytime chargen fs dtspc \ exec comsat talk finger uucp name xaudio netstat ufsd rexd \ systat sun-dr uuidgen krb5_prop 100068 100146 100147 100150 \ 100221 100232 100235 kerbd rstatd rusersd sprayd walld \ printer shell login telnet ftp tftp 100083 100229 100230 \ 100242 100234 100134 100155 rquotad 100424 100422; do check_inetd_service "${service_name}" "disabled" done } audit_legacy_init () { print_function "audit_legacy_init" string="Init Services" check_message "${string}" for service_name in llc2 pcmcia ppd slpd boot.server autoinstall \ power bdconfig cachefs.daemon cacheos.finish asppp uucp flashprom \ PRESERVE ncalogd ncad ab2mgr dmi mipagent nfs.client autofs rpc \ directory ldap.client lp spc volmgt dtlogin ncakmod samba dhcp \ nfs.server kdc.master kdc apache snmpdx; do check_initd_service "${service_name}" "disabled" done } audit_legacy () { print_function 'audit_legacy' string="Legacy Inet/Init Services" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_rctcp "timed" "off" check_subserver "telnet" "tcp6" "off" check_subserver "exec" "tcp6" "off" check_subserver "daytime" "udp" "off" check_subserver "shell" "tcp6" "off" check_subserver "cmsd" "sunrpc_tcp" "off" check_subserver "ttdbserver" "sunrpc_tcp" "off" check_subserver "uucp" "tcp" "off" check_subserver "time" "udp" "off" check_subserver "login" "tcp" "off" check_subserver "talk" "udp" "off" check_subserver "ntalk" "udp" "off" check_subserver "ftp" "tcp6" "off" check_subserver "chargen" "tcp" "off" check_subserver "discard" "tcp" "off" check_subserver "dtspc" "tcp" "off" check_subserver "echo" "tcp" "off" check_subserver "echo" "udp" "off" check_subserver "pcnfsd" "udp" "off" check_subserver "rstatd" "udp" "off" check_subserver "rusersd" "udp" "off" check_subserver "rwalld" "udp" "off" check_subserver "sprayd" "udp" "off" check_subserver "klogin" "tcp" "off" check_subserver "rquotad" "udp" "off" check_subserver "tftp" "udp" "off" check_subserver "imap2" "tcp" "off" check_subserver "pop3" "tcp" "off" check_subserver "finger" "tcp" "off" check_subserver "instsrv" "tcp" "off" else if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" != "11" ]; then audit_legacy_inet audit_legacy_init fi else audit_legacy_inet audit_legacy_init fi fi else na_message "${string}" fi } ================================================ FILE: modules/services/audit_other_daemons.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_other_daemons # # Check chkconfig and other daemons # # Refer to Section(s) 1.2.4-5 Page(s) 36-7 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.2.4-5 Page(s) 34-5 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.2.5,2.2.11 Page(s) 53,122 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.16 Page(s) 63-4 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.2.11 Page(s) 103 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.1.13 Page(s) 264-4 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_other_daemons () { print_function "audit_other_daemons" string="Miscellaneous Services" check_message "${string}" if [ "${os_name}" = "Linux" ]; then for service_name in wu-ftpd ftp vsftpd aaeventd tftp acpid \ amd arptables_jg arpwatch atd netfs irda isdn bluetooth \ capi conman cpuspeed cryrus-imapd dc_client dc_server \ dhcdbd dhcp6s dhcrelay chargen chargen-udp dovecot dund \ gpm hidd hplip ibmasm innd ip6tables lisa lm_sensors \ mailman mctrans mdmonitor mdmpd microcode_ctl mysqld \ netplugd network NetworkManager openibd yum-updatesd \ pand postfix psacct mutipathd daytime daytime-udp radiusd \ radvd rdisc readahead_early readahead_later rhnsd rpcgssd \ rpcimapd rpcsvcgssd rstatd rusersd rwhod saslauthd \ settroubleshoot smartd spamassasin echo echo-udp time \ time-udp vnc svcgssd rpmconfigcheck rsh rsync rsyncd \ saslauthd powerd raw rexec rlogin rpasswdd openct \ ipxmount joystick esound evms fam gpm gssd pcscd \ tog-pegasus tux wpa_supplicant zebra ncpfs; do check_linux_service "${service_name}" "off" done else na_message "${string}" fi } ================================================ FILE: modules/services/audit_postgresql.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_postgresql # # Turn off postgresql if not required # Recommend removing this from base install as it slows down patching significantly #. audit_postgresql () { print_function "audit_postgresql" string="PostgreSQL Database" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then for service_name in "svc:/application/database/postgresql_83:default_32bit" \ "svc:/application/database/postgresql_83:default_64bit" \ "svc:/application/database/postgresql:version_81" \ "svc:/application/database/postgresql:version_82" \ "svc:/application/database/postgresql:version_82_64bit"; do check_sunos_service "${service_name}" "disabled" done fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "postgresql" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/services/audit_rarp.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_rarp # # rarp: Turn off rarp if not in use # rarp is required for jumpstart servers #. audit_rarp () { print_function "audit_rarp" string="RARP Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/rarp:default" "disabled" fi fi if [ "${os_name}" = "Linux" ]; then check_linux_service "rarpd" "off" fi else na_message "${string}" fi } ================================================ FILE: modules/services/audit_snmp.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_snmp # # Check SNMP configuration # # Refer to Section(s) 3.15 Page(s) 69 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.15 Page(s) 81-2 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.15 Page(s) 71-2 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.2.14 Page(s) 114 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.14 Page(s) 61-2 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.3.7,18-21 Page(s) 41-2,55-60 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 1.13 Page(s) 43-4 CIS ESX Server 4 Benchmark v1.1.0 # Refer to Section(s) 2.2.14 Page(s) 106 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.2.14 Page(s) 114 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.1.15 Page(s) 267-9 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_snmp () { print_function "audit_snmp" string="SNMP Daemons and Log Permissions" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "AIX" ] || [ "${os_name}" = "VMkernel" ]; then if [ "$snmpd_disable" = "yes" ]; then if [ "${os_name}" = "VMkernel" ]; then log_file="snmpstatus" backup_file="${work_dir}/${log_file}" current_value=$( esxcli system snmp get | grep Enable | awk '{print $2}' ) if [ "${audit_mode}" != "2" ]; then if [ "${current_value}" = "true" ]; then if [ "${audit_mode}" = "0" ]; then echo "${current_value}" > "${backup_file}" verbose_message "SNMP to disabled" "set" esxcli system snmp set --enable="false" fi if [ "${audit_mode}" = "1" ]; then inc_insecure "SNMP is not enabled" fix_message "esxcli system snmp set --enable=\"false\"" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "SNMP is disabled" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then previous_value=$( cat "${restore_file}" ) if [ "${previous_value}" != "${current_value}" ]; then verbose_message "Restoring: SNMP to ${previous_value}" esxcli system snmp set --enable="${previous_value}" fi fi fi fi if [ "${os_name}" = "AIX" ]; then for service_name in snmpd dpid2 hostmibd snmpmibd aixmibd; do check_rctcp "${service_name}" "off" done for check_file in /var/tmp/snmpd.log /var/tmp/hostmibd.log \ /var/tmp/dpid2.log /var/ct/RMstart.log /smit.log; do check_file_perms "${check_file}" "0640" "root" "system" done check_file_perms "/var/adm/ras" "0700" "root" "system" fi if [ "${os_name}" = "SunOS" ]; then verbose_message "SNMP Daemons" "check" if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then for service_name in "svc:/application/management/seaport:default" \ "svc:/application/management/snmpdx:default" \ "svc:/application/management/dmi:default" \ "svc:/application/management/sma:default"; do check_sunos_service "${service_name}" "disabled" done else for service_name in init.dmi init.sma init.snmpdx; do check_sunos_service "${service_name}" "disabled" done fi fi if [ "${os_name}" = "Linux" ]; then for service_name in snmp snmptrapd; do check_linux_service "${service_name}" "off" done check_append_file "/etc/snmp/snmpd.conf" "com2sec notConfigUser default public" "hash" check_linux_package "uninstall" "net-snmp" fi else if [ "${os_name}" = "AIX" ]; then for check_file in /var/tmp/snmpd.log /var/tmp/hostmibd.log \ /var/tmp/dpid2.log /var/ct/RMstart.log /smit.log; do check_file_perms "${check_file}" "0640" "root" "system" done check_file_perms "/var/adm/ras" "0700" "root" "system" fi fi else na_message "${string}" fi } ================================================ FILE: modules/services/audit_unconfined_daemons.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2009 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_unconfined_daemons # # Check for unconfined daemons # # Refer to Section(s) 1.4.6 Page(s) 40 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 1.4.6 Page(s) 45-6 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.4.6 Page(s) 43 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 1.6.1.4 Page(s) 68 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_unconfined_daemons () { print_function "audit_unconfined_daemons" string="Unconfined Daemons" check_message "${string}" if [ "${os_name}" = "Linux" ]; then command="ps -eZ 2> /dev/null | grep \"initrc\" | grep -Evw \"tr|ps|egrep|bash|awk\" | tr ':' ' ' | awk '{ print \$NF }'" command_message "${command}" daemon_check=$( eval "${command}" ) if [ -z "${daemon_check}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Unconfined daemons \"${daemon_check}\"" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "No unconfined daemons" fi fi else na_message "${string}" fi } ================================================ FILE: modules/ssh/audit_root_ssh_keys.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_root_ssh_keys # # Make sure there are not ssh keys for root #. audit_root_ssh_keys () { print_function "audit_root_ssh_keys" string="Root SSH keys" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then if [ "${audit_mode}" != 2 ]; then command="grep '^root' /etc/passwd | cut -f6 -d:" command_message "${command}" root_home=$( eval "${command}" ) for check_file in $root_home/.ssh/authorized_keys $root_home/.ssh/authorized_keys2; do if [ -f "${check_file}" ]; then command="wc -l \"${check_file}\" | awk '{print \$1}'" command_message "${command}" key_check=$( eval "${command}" ) if [ "${key_check}" -ge 1 ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Keys file \"${check_file}\" ${exists}" fix_message "mv ${check_file} ${check_file}.disabled" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" remove_message "Keys file \"${check_file}\"" if [ -f "${check_file}" ]; then rm "${check_file}" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Keys file \"${check_file}\" does not contain any keys" fi fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Keys file \"${check_file}\" does not exist" fi fi done else restore_file "${check_file}" "${restore_dir}" fi else na_message "${string}" fi } ================================================ FILE: modules/ssh/audit_ssh_config.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ssh_config # # Check SSH config # # Refer to Section(s) 6.2.1-15 Page(s) 127-37 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.2.1-15 Page(s) 147-59 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 6.2.1-15 Page(s) 130-41 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.2.1-16 Page(s) 218-37 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 9.2.1-15 Page(s) 121-31 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.4.14.9 Page(s) 57-60 CIS OS X 10.5 Benchmark v1.1.0 # Refer to Section(s) 1.2 Page(s) 2-3 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 6.3-7 Page(s) 47-51 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.1.1-11 Page(s) 78-87 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 5.2.1-16 Page(s) 201-18 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 5.2.1-16 Page(s) 213-31 CIS Ubuntu 16.04 Benchmark v2.0.0 # Refer to Section(s) 5.1.1-22 Page(s) 523-78 CIS Ubuntu 24.04 Benchmark v1.0.0 # # Refer to http://pubs.vmware.com/vsphere-55/index.jsp?topic=%2Fcom.vmware.vsphere.security.doc%2FGUID-12E27BF3-3769-4665-8769-DA76C2BC9FFE.html # Refer to https://wiki.mozilla.org/Security/Guidelines/OpenSSH #. audit_ssh_config () { print_function "audit_ssh_config" string="SSH Config" check_message "${string}" if [ "${os_name}" = "VMkernel" ] || [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "VMkernel" ]; then check_linux_service "SSH" "off" fi for check_file in /etc/sshd_config /etc/ssh/sshd_config /usr/local/etc/sshd_config /opt/local/ssh/sshd_config; do if [ -f "${check_file}" ]; then if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "Darwin" ]; then check_file_value "is" "${check_file}" "GSSAPIAuthentication" "space" "yes" "hash" check_file_value "is" "${check_file}" "GSSAPICleanupCredentials" "space" "yes" "hash" fi check_file_perms "${check_file}" "0600" "root" "root" check_file_value "is" "${check_file}" "UseLogin" "space" "no" "hash" check_file_value "is" "${check_file}" "X11Forwarding" "space" "no" "hash" check_file_value "is" "${check_file}" "MaxAuthTries" "space" "4" "hash" check_file_value "is" "${check_file}" "MaxAuthTriesLog" "space" "0" "hash" check_file_value "is" "${check_file}" "RhostsAuthentication" "space" "no" "hash" check_file_value "is" "${check_file}" "IgnoreRhosts" "space" "yes" "hash" check_file_value "is" "${check_file}" "StrictModes" "space" "yes" "hash" check_file_value "is" "${check_file}" "AllowTcpForwarding" "space" "no" "hash" check_file_value "is" "${check_file}" "DisableForwarding" "space" "yes" "hash" check_file_value "is" "${check_file}" "Protocol" "space" "${ssh_protocol}" "hash" if [ "$ssh_protocol" = "1" ]; then check_file_value "is" "${check_file}" "ServerKeyBits" "space" "$ssh_key_size" "hash" fi check_file_value "is" "${check_file}" "GatewayPorts" "space" "no" "hash" check_file_value "is" "${check_file}" "RhostsRSAAuthentication" "space" "no" "hash" check_file_value "is" "${check_file}" "PermitRootLogin" "space" "no" "hash" check_file_value "is" "${check_file}" "PermitEmptyPasswords" "space" "no" "hash" check_file_value "is" "${check_file}" "PermitUserEnvironment" "space" "no" "hash" check_file_value "is" "${check_file}" "HostbasedAuthentication" "space" "no" "hash" check_file_value "is" "${check_file}" "PrintMotd" "space" "no" "hash" check_file_value "is" "${check_file}" "ClientAliveInterval" "space" "300" "hash" check_file_value "is" "${check_file}" "ClientAliveCountMax" "space" "0" "hash" check_file_value "is" "${check_file}" "RSAAuthentication" "space" "no" "hash" check_file_value "is" "${check_file}" "Banner" "space" "/etc/issue" "hash" check_file_value "is" "${check_file}" "LogLevel" "space" "VERBOSE" "hash" if [ ! "${ssh_allowusers}" = "" ]; then check_file_value "is" "${check_file}" "AllowUsers" "space" "${ssh_allowusers}" "hash" fi if [ ! "${ssh_allowgroups}" = "" ]; then check_file_value "is" "${check_file}" "AllowUsers" "space" "${ssh_allowgroups}" "hash" fi if [ ! "${ssh_denyusers}" = "" ]; then check_file_value "is" "${check_file}" "DenyUsers" "space" "${ssh_denyusers}" "hash" fi if [ ! "${ssh_denygroups}" = "" ]; then check_file_value "is" "${check_file}" "DenyGroups" "space" "${ssh_denygroups}" "hash" fi if [ "$ssh_sandbox" = "yes" ]; then check_file_value "is" "${check_file}" "UsePrivilegeSeparation" "space" "sandbox" "hash" else check_file_value "is" "${check_file}" "UsePrivilegeSeparation" "space" "yes" "hash" fi if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 24 ]; then check_file_value "is" "${check_file}" "MaxStartups" "space" "10:30:60" "hash" check_file_value "is" "${check_file}" "MaxSessions" "space" "10" "hash" fi check_file_value "is" "${check_file}" "LoginGraceTime" "space" "60" "hash" # Check for kerbero s check_file="/etc/krb5/krb5.conf" if [ -f "${check_file}" ]; then admin_check=$( grep -v '^#' "${check _file}" | grep "admin_server" | cut -f2 -d= | sed 's/ //g' | wc -l | sed 's/ //g' ) if [ "$admin_server" != "0" ]; then check_file="/etc/ssh/sshd_config" check_file_value "is" "${check_file}" "UsePAM" "space" "yes" "hash" check_file_value "is" "${check_file}" "GSSAPIAuthentication" "space" "yes" "hash" check_file_value "is" "${check_file}" "GSSAPIKeyExchange" "space" "yes" "hash" check_file_value "is" "${check_file}" "GSSAPIStoreDelegatedCredentials" "space" "yes" "hash" fi fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/rc.conf" "sshd_enable" "eq" "YES" "hash" fi fi fi done verbose_message "SSH MACs" "check" ignore_list="" command="sshd -T 2> /dev/null | grep \"^macs\" | sed \"s/,/ /g\" | sed \"s/^macs //g\"" command_message "${command}" mac_list=$( eval "${command}" ) for mac_name in ${mac_list}; do case "${mac_name}" in hmac-md5|hmac-md5-96|hmac-ripemd160|hmac-sha1-96|umac-64@openssh.com|hmac-md5-etm@openssh.com|hmac-md5-96-etm@openssh.com|hmac-ripemd160-etm@openssh.com|mac-sha1-96-etm@openssh.com|umac-64-etm@openssh.com|umac-128-etm@openssh.com) inc_insecure "MAC ${mac_name} is enabled" if [ "${ignore_list}" = "" ]; then ignore_list="${mac_name}" else ignore_list="${ignore_list},${mac_name}" fi ;; *) inc_secure "MAC ${mac_name} is enabled" ;; esac done if [ ! "${ignore_list}" = "" ]; then for check_file in /etc/sshd_config /etc/ssh/sshd_config /usr/local/etc/sshd_config /opt/local/ssh/sshd_config; do if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "MACs" "space" "-${ignore_list}" "hash" fi done fi check_message "SSH KexAlgorithms" ignore_list="" command="sshd -T 2> /dev/null | grep \"^kexalgorithms\" | sed \"s/,/ /g\" | sed \"s/^kexalgorithms //g\"" command_message "${command}" kex_list=$( eval "${command}" ) for kex_name in ${kex_list}; do case "${kex_name}" in diffie-hellman-group1-sha1|diffie-hellman-group14-sha1|diffie-hellman-group-exchange-sha1) inc_insecure "Kex Algoritm ${kex_name} is enabled" if [ "${ignore_list}" = "" ]; then ignore_list="${kex_name}" else ignore_list="${ignore_list},${kex_name}" fi ;; *) inc_secure "Kex Algoritm ${kex_name} is enabled" ;; esac done if [ ! "${ignore_list}" = "" ]; then for check_file in /etc/sshd_config /etc/ssh/sshd_config /usr/local/etc/sshd_config /opt/local/ssh/sshd_config; do if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "KexAlgorithms" "space" "-${ignore_list}" "hash" fi done fi check_message "SSH Ciphers" ignore_list="" command="sshd -T 2> /dev/null | grep \"^ciphers\" | sed \"s/,/ /g\" | sed \"s/^ciphers //g\"" command_message "${command}" cipher_list=$( eval "${command}" ) for cipher_name in ${cipher_list}; do case "${cipher_name}" in 3des-cbc|aes128-cbc|aes192-cbc|aes256-cbc) inc_insecure "Cipher ${cipher_name} is enabled" if [ "${ignore_list}" = "" ]; then ignore_list="${cipher_name}" else ignore_list="${ignore_list},${cipher_name}" fi ;; *) inc_secure "Cipher ${cipher_name} is enabled" ;; esac done if [ ! "${ignore_list}" = "" ]; then for check_file in /etc/sshd_config /etc/ssh/sshd_config /usr/local/etc/sshd_config /opt/local/ssh/sshd_config; do if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "Ciphers" "space" "-${ignore_list}" "hash" fi done fi else na_message "SSH" fi } ================================================ FILE: modules/ssh/audit_ssh_forwarding.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ssh_forwarding # # This one is optional, generally required for apps # # Refer to Section(s) 11.1 Page(s) 142-3 CIS Solaris 10 Benchmark v1.1.0 #. audit_ssh_forwarding () { print_function "audit_ssh_forwarding" string="SSH Forwarding" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then if [ "${os_name}" = "Darwin" ]; then check_file="/etc/sshd_config" else check_file="/etc/ssh/sshd_config" fi check_file_value "is" "${check_file}" "AllowTcpForwarding" "space" "no" "hash" else na_message "${string}" fi } ================================================ FILE: modules/ssh/audit_ssh_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ssh_perms # # Check SSH file permission for keys etc #. audit_ssh_perms () { print_function "audit_ssh_perms" string="SSH Permissions" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then for check_dir in /etc/ssh /usr/local/etc/ssh; do if [ -d "${check_dir}" ]; then command="find \"${check_dir}\" -name \"*_key\" -type f" command_message "${command}" file_list=$( eval "${command}" ) for check_file in ${file_list}; do check_file_perms "${check_file}" "0600" "root" "root" done command="find \"${check_dir}\" -name \"*.pub\" -type f" command_message "${command}" file_list=$( eval "${command}" ) for check_file in ${file_list}; do check_file_perms "${check_file}" "0640" "root" "root" done fi done check_message "User SSH Permissions" if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi while IFS=":" read -r user _ uid gid _ home shell; do if [ -d "${home}/.ssh" ]; then check_file_perms "${home}/.ssh" "0700" "${uid}" "${gid}" command="find \"${home}/.ssh\" -type f" command_message "${command}" file_list=$( eval "${command}" ) for check_file in ${file_list}; do check_file_perms "${check_file}" "0600" "${uid}" "${gid}" done fi done < /etc/passwd else na_message "${string}" fi } ================================================ FILE: modules/sudo/audit_sudo_authenticate.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sudo_authenticate # # Check sudo authenticate # # Refer to Section(s) 5.2.5 Page(s) 592-3 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_sudo_authenticate () { print_function "audit_sudo_authenticate" string="Sudo authenticate" check_message "${string}" if [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi check_file="/etc/sudoers" if [ -f "${check_file}" ]; then command="grep \"^[^#].*\\!authenticate\" < \"${check_file}\"" command_message "${command}" auth_test=$( eval "${command}" ) if [ -n "${auth_test}" ]; then inc_insecure "Re-authentication is not disabled for sudo in ${check_file}" else inc_secure "Re-authentication is disabled for sudo in ${check_file}" fi check_file_perms "${check_file}" "440" "root" "${wheel_group}" fi if [ -d "/etc/sudoers.d" ]; then command="find /etc/sudoers.d -type file" command_message "${command}" file_list=$( eval "${command}" ) for check_file in ${file_list}; do command="grep \"^[^#].*\\!authenticate\" < \"${check_file}\"" command_message "${command}" auth_test=$( eval "${command}" ) if [ -n "${auth_test}" ]; then inc_insecure "Re-authentication is not disabled for sudo in ${check_file}" else inc_secure "Re-authentication is disabled for sudo in ${check_file}" fi check_file_perms "${check_file}" "440" "root" "${wheel_group}" done fi else na_message "${string}" fi } ================================================ FILE: modules/sudo/audit_sudo_logfile.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sudo_logfile # # Check sudo logfile # # Refer to Section(s) 5.2.3 Page(s) 585-7 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_sudo_logfile () { print_function "audit_sudo_logfile" string="Sudo logfile" check_message "${string}" if [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ -d "/etc/sudoers.d" ]; then check_file="/etc/sudoers.d/logfile" else check_file="/etc/sudoers" fi check_file_value "is" "${check_file}" "Defaults logfile" "eq" "/var/log/sudo.log" "hash" check_file_perms "${check_file}" "440" "root" "${wheel_group}" else na_message "${string}" fi } ================================================ FILE: modules/sudo/audit_sudo_nopassword.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sudo_nopassword # # Check sudo NOPASSWD # # Refer to Section(s) 5.2.4 Page(s) 588-9 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_sudo_nopassword () { print_function "audit_sudo_nopassword" string="Sudo NOPASSWD" check_message "${string}" if [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi check_file="/etc/sudoers" if [ -f "${check_file}" ]; then command="grep \"^[^#].*NOPASSWD\" < \"${check_file}\"" command_message "${command}" auth_test=$( eval "${command}" ) if [ -n "${auth_test}" ]; then inc_insecure "NOPASSWD entry for sudo in ${check_file}" else inc_secure "No NOPASSWD entry for sudo in ${check_file}" fi check_file_perms "${check_file}" "440" "root" "${wheel_group}" fi if [ -d "/etc/sudoers.d" ]; then command="find /etc/sudoers.d -type file" command_message "${command}" file_list=$( eval "${command}" ) for check_file in ${file_list}; do command="grep \"^[^#].*NOPASSWD\" < \"${check_file}\"" command_message "${command}" auth_test=$( eval "${command}" ) if [ -n "${auth_test}" ]; then inc_insecure "NOPASSWD entry for sudo in ${check_file}" else inc_secure "No NOPASSWD entry for sudo in ${check_file}" fi check_file_perms "${check_file}" "440" "root" "${wheel_group}" done fi else na_message "${string}" fi } ================================================ FILE: modules/sudo/audit_sudo_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sudo_perms # # Check sudo file permissions #. audit_sudo_perms () { print_function "audit_sudo_perms" string="Sudo file permissions" check_message "${string}" if [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then check_file="/etc/sudoers" if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "440" "root" "${wheel_group}" fi if [ -d "/etc/sudoers.d" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "May require sudo to check" "notice" fi file_list=$( find /etc/sudoers.d -type f 2> /dev/null ) for check_file in ${file_list}; do check_file_perms "${check_file}" "440" "root" "${wheel_group}" done fi else na_message "${string}" fi } ================================================ FILE: modules/sudo/audit_sudo_timeout.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sudo_timeout # # Check sudo timeout # # Refer to Section(s) 5.1 Page(s) 48-9 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 5.3 Page(s) 128-9 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 5.4 Page(s) 343-5 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 # Refer to Section(s) 5.2.6 Page(s) 592-3 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_sudo_timeout () { print_function "audit_sudo_timeout" string="Sudo timeout" check_message "${string}" if [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ -d "/etc/sudoers.d" ]; then check_file="/etc/sudoers.d/timeout" else check_file="/etc/sudoers" fi check_file_value "is" "${check_file}" "Defaults timestamp_timeout" "eq" "15" "hash" check_file_perms "${check_file}" "440" "root" "${wheel_group}" else na_message "${string}" fi } ================================================ FILE: modules/sudo/audit_sudo_timestamp.sh ================================================ #!/bin/sh -eu # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sudo_timestanp # # Check sudo timestamp # # Refer to Section(s) 5.5 Page(s) 346-7 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 # Refer to Section(s) 5.2.6 Page(s) 592-3 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_sudo_timestamp () { print_function "audit_sudo_timestamp" string="Sudo timestamp" check_message "${string}" if [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi command="sudo --version | head -1 | awk '{print \$3}' | cut -f1 -d." command_message "${command}" major_ver=$( eval "${command}" ) command="sudo --version | head -1 | awk '{print \$3}' | cut -f2 -d." command_message "${command}" minor_ver=$( eval "${command}" ) check_sudo="0" if [ "$major_ver" -gt 1 ]; then check_sudo="1" else if [ "$major_ver" -eq 1 ] && [ "$minor_ver" -ge 8 ]; then check_sudo="1" fi fi if [ -d "/etc/sudoers.d" ]; then check_file="/etc/sudoers.d/timestamp" else check_file="/etc/sudoers" fi if [ "$check_sudo" = "1" ]; then check_file_value "is" "${check_file}" "Defaults timestamp_type" "eq" "tty" "hash" check_file_perms "${check_file}" "440" "root" "${wheel_group}" fi else na_message "${string}" fi } ================================================ FILE: modules/sudo/audit_sudo_usepty.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_sudo_usepty # # Check sudo use_pty # # Refer to Section(s) 5.2.2 Page(s) 582-4 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_sudo_usepty () { print_function "audit_sudo_usepty" string="Sudo use_pty" check_message "${string}" if [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "SunOS" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ -d "/etc/sudoers.d" ]; then check_file="/etc/sudoers.d/use_pty" else check_file="/etc/sudoers" fi check_append_file "${check_file}" "Defaults use_pty" "hash" check_file_perms "${check_file}" "440" "root" "${wheel_group}" else na_message "${string}" fi } ================================================ FILE: modules/sudo/audit_wheel_sudo.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2028 # shellcheck disable=SC2154 # audit_wheel_sudo # # Check wheel group settings in sudoers #. audit_wheel_sudo () { print_function "audit_wheel_sudo" string="Sudoers group settings" check_message "${string}" temp_file="${temp_dir}/audit_wheel_sudo" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then for check_dir in /etc /usr/local/etc /usr/sfw/etc /opt/csw/etc; do check_dir="${check_dir}/sudoers.d" if [ -d "${check_dir}" ]; then check_files=$( find "${check_dir}" -type f ) for check_file in ${check_file}s; do check_file_perms "${check_file}" "0440" "root" "root" if [ "${audit_mode}" != 2 ]; then wheel_groups=$( grep NOPASSWD "${check_file}" | grep ALL | grep -v '^#' | awk '{print $1}' ) for wheel_group in ${wheel_groups} ; do if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking NOPASSWD for ${wheel_group} in ${check_file}" echo " lineinfile:" echo " path: ${check_file}" echo " regexp: ''(.*NOPASSWD.*)'" echo " replace: '#\1'" echo "" fi lock_command="sed 's/^\(%.*NOPASSWD.*\)/#\1/g' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file}" lock_message="Disabling group \"${wheel_group}\" NOPASSWD entry" if [ "${audit_mode}" = 1 ]; then inc_insecure "Group ${wheel_group} does not require password to escalate privileges" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi done else restore_file "${check_file}" "${restore_dir}" fi done fi check_file="${check_dir}/sudoers" if [ -f "${check_file}" ]; then check_file_perms ${check_file} 0440 root root if [ "${audit_mode}" != 2 ]; then wheel_groups=$( grep NOPASSWD "${check_file}" | grep ALL | grep -v '^#' | awk '{print $1}' ) for wheel_group in ${wheel_groups} ; do if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking NOPASSWD for ${wheel_group} in ${check_file}" echo " lineinfile:" echo " path: ${check_file}" echo " regexp: ''(.*NOPASSWD.*)'" echo " replace: '#\1'" echo "" fi lock_command="sed 's/^\(%.*NOPASSWD.*\)/#\1/g' < ${check_file} > ${temp_file} ; cat ${temp_file} > ${check_file}" lock_message="Disabling group \"${wheel_group}\" NOPASSWD entry" if [ "${audit_mode}" = 1 ]; then inc_insecure "Group \"${wheel_group}\" does not require password to escalate privileges" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi done else restore_file "${check_file}" "${restore_dir}" fi fi done else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_apocd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_apocd # # Check APOC # # Turn off apocd #. audit_apocd () { print_function "audit_apocd" string="APOC Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/apocd/udp:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_audit_class.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_audit_class # # Check audit class # # Refer to Section(s) 4.1-5 Page(s) 39-45 CIS Solaris 11.1 v1.0.0 #. audit_audit_class () { print_function "audit_audit_class" string="Audit Class" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "11" ]; then audit_create_class audit_network_connections audit_file_metadata audit_privilege_events fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_bpcd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_bpcd # # Turn off bpcd #. audit_bpcd () { print_function "audit_bpcd" string="BPC Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/bpcd/tcp:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_bpjava_msvc.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_bpjava_msvc # # Turn off bpjava-msvc if not required. It is associated with NetBackup. #. audit_bpjava_msvc () { print_function "audit_bpjava_msvc" string="BPJava Service" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/bpjava-msvc/tcp:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_cde_banner.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cde_banner # # Check CDE Warning Banner # # Refer to Section(s) 8.2 Page(s) 112-3 CIS Solaris 10 v5.1.0 #. audit_cde_banner () { print_function "audit_cde_banner" string="CDE Warning Banner" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then for cde_file in /usr/dt/config/*/Xresources ; do dir_name=$( dirname" ${cde_file}" | sed "s/usr/etc/" ) check_file="${dir_name}/Xresources" if [ -f "${check_file}" ]; then check_file_value "is" "${check_file}" "Dtlogin*greeting.labelString" "colon" "Authorized uses only" "star" check_file_value "is" "${check_file}" "Dtlogin*greeting.persLabelString" "colon" "Authorized uses only" "star" fi done else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_cde_cal.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cde_cal () { # # Check Local CDE Calendar Manager # # Refer to Section(s) 2.1.2 Page(s) 18-9 CIS Solaris 10 v5.1.0 #. audit_cde_cal () { print_function "audit_cde_cal" string="Local CDE Calendar Manager" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/network/rpc/cde-calendar-manager:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_cde_print.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cde_print # # CDE Printing services. Not required unless running CDE applications. #. audit_cde_print () { print_function "audit_cde_print" string="CDE Print" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/application/cde-printinfo:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_cde_screen_lock.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cde_screen_lock # # Check Screen Lock for CDE Users # # Refer to Section(s) 6.7 Page(s) 91-2 CIS Solaris 10 Benchmark v5.1.0 #. audit_cde_screen_lock () { print_function "audit_cde_screen_lock" string="Screen Lock for CDE Users" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then file_list=$( find /usr/dt/config/*/sys.resources -t file -maxdepth 1 2> /dev/null ) for cde_file in ${file_list}; do dir_name=$( dirname "$cde_file" | sed "s/usr/etc/" ) if [ ! -d "${dir_name}" ]; then mkdir -p "${dir_name}" fi check_file="${dir_name}/sys.resources" check_file_value "is" "${check_file}" "dtsession*saverTimeout" "colon" " 10" "star" check_file_value "is" "${check_file}" "dtsession*lockTimeout" "colon" " 10" "star" check_file_perms "${check_file}" "0444" "root" "sys" done else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_cde_spc.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cde_spc # # CDE Subprocess control. Not required unless running CDE applications. #. audit_cde_spc () { print_function "audit_cde_spc" string="CDE Subprocess control" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/network/cde-spc:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_cde_ttdb.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_cde_ttdb # # Check CDE ToolTalk Database Server # # Refer to Section(s) 2.1.1 Page(s) 17-8 CIS Solaris 10 v5.1.0 #. audit_cde_ttdb () { print_function "audit_cde_ttdb" string="CDE ToolTalk Database Server" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/network/rpc/cde-ttdbserver:tcp" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_create_class.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_create_class # # Creating Audit Classes improves the auditing capabilities of Solaris. # # Refer to Section(s) 4.1-5 Page(s) 39-45 CIS Solaris 11.1 v1.0.0 #. audit_create_class () { print_function "audit_create_class" string="Audit Classes" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file="/etc/security/audit_class" if [ -f "${check_file}" ]; then check_append_file "${check_file}" "0x0100000000000000:lck:Security Lockdown" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_dfstab.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dfstab # # Check dfstab # # Refer to Section(s) 10.2 Page(s) 138-9 CIS Solaris 10 Benchmark v1.1.0 #. audit_dfstab () { print_function "audit_dfstab" string="Full Path Names in Exports" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then replace_file_value "/etc/dfs/dfstab" "share" "/usr/bin/share" "start" else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_echo.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_echo # # Turn off echo and chargen services #. audit_echo () { print_function "audit_echo" string="Echo and Chargen Services" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then for service_name in "svc:/network/echo:dgram" \ "svc:/network/echo:stream" "svc:/network/time:dgram" \ "svc:/network/time:stream" "svc:/network/tname:default" \ "svc:/network/comsat:default" "svc:/network/discard:dgram" \ "svc:/network/discard:stream" "svc:/network/chargen:dgram" \ "svc:/network/chargen:stream" "svc:/network/rpc/spray:default" \ "svc:/network/daytime:dgram" "svc:/network/daytime:stream" \ "svc:/network/talk:default"; do check_sunos_service "${service_name}" "disabled" done fi else na_message "${string}" fi # if [ "${os_name}" = "Linux" ]; then # verbose_message "Telnet and Rlogin Services" # for service_name in telnet login rlogin rsh shell; do # check_linux_service ${service_name} off # done # fi } ================================================ FILE: modules/sunos/audit_eeprom_security.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_eeprom_security # # Check EEPROM security # # Refer to Section(s) 6.15 Page(s) 59-60 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 6.12 Page(s) 97-8 CIS Solaris 10 Benchmark v5.1.0 #. audit_eeprom_security () { print_function "audit_eeprom_security" string="EEPROM Password" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${audit_mode}" = 2 ]; then echo "EEPROM password to none" "restore" eeprom security-mode=none fi if [ "${audit_mode}" != 2 ]; then eeprom_check=$( eeprom security-mode | awk -F= '{ print $2 }' ) if [ "${eeprom_check}" = "none" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "EEPROM password is not enabled" fix_message "eeprom security-mode=command" fix_message "eeprom security-#badlogins=0" fi if [ "${audit_mode}" = 0 ]; then eeprom security-mode=command eeprom security-#badlogins=0 fi else if [ "${audit_mode}" = 1 ];then inc_secure "EEPROM password is enabled" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_extended_attributes.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_extended_attributes # # Check extended attributes # # Refer to Section(s) 9.25 Page(s) 90-1 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.25 Page(s) 136-7 CIS Solaris 10 Benchmark v1.1.0 #. audit_extended_attributes () { print_function "audit_extended_attributes" string="Extended Attributes" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${audit_mode}" = 1 ]; then file_list=$( find / \( -fstype nfs -o -fstype cachefs \ -o -fstype autofs -o -fstype ctfs -o -fstype mntfs \ -o -fstype objfs -o -fstype proc \) -prune \ -o -xattr -print ) for check_file in ${file_list}; do inc_insecure "File \"${check_file}\" has extended attributes" done fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_gss.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_gss # # Check Generic Security Services # # Refer to Section(s) 2.7 Page(s) 19-20 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 2.2.7 Page(s) 27 CIS Solaris 10 Benchmark v5.1.0 #. audit_gss () { print_function "audit_gss" string="Generic Security Services" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/rpc/gss" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_ipadm_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ipadm_value # # Code to drive ipadm on Solaris 11 #. audit_ipadm_value () { print_function "audit_ipadm_value" string="IPadm Value" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "11" ]; then ipadm_name="${1}" ipadm_property="${2}" correct_value="${3}" command="ipadm show-prop -p \"${ipadm_name}\" -co current \"${ipadm_property}\"" command_message "${command}" current_value=$( eval "${command}" ) file_header="ipadm" log_file="${work_dir}/${file_header}.log" if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${file_header}.log" if [ -f "${restore_file}" ]; then restore_property=$( grep "${ipadm_property}," "${restore_file}" | cut -f2 -d',' ) restore_value=$( grep "${ipadm_property}," "${restore_file}" | cut -f3 -d',' ) restore_check=$( expr "${restore_property}" : "[A-z]" ) if [ "${restore_check}" = 1 ]; then if [ "${current_value}" != "${restore_value}" ]; then restore_message "\"${ipadm_name}\" \"${ipadm_property}\" to \"${restore_value}\"" eval "ipadm set-prop -p ${ipadm_name}=${restore_value} ${ipadm_property}" fi fi fi else info_message "Value of \"${ipadm_name}\" for \"${ipadm_property}\" is \"${correct_value}\"" fi if [ "${current_value}" -ne "${correct_value}" ]; then command_line="ipadm set-prop -p ${ipadm_name}=${correct_value} ${ipadm_property}" if [ "${audit_mode}" = 1 ]; then inc_insecure "Value of \"${ipadm_name} ${ipadm_property}\" not set to \"${correct_value}\"" fix_message "${command_line}" else if [ "${audit_mode}" = 0 ]; then info_message "Value of \"${ipadm_name} ${ipadm_property}\" to \"${correct_value}\"" echo "${ipadm_name},${ipadm_property},${correct_value}" >> "${log_file}" eval "${command_line}" fi fi else if [ "${audit_mode}" != 2 ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "Value of \"${ipadm_name} ${ipadm_property}\" already set to \"${correct_value}\"" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_keyserv.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_keyserv # # Refer to Section(s) 2.3 Page(s) 16-17 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 2.2.1 Page(s) 23 CIS Solaris 10 Benchmark v5.1.0 #. audit_keyserv () { print_function "audit_keyserv" string="RPC Encryption Key" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/rpc/keyserv" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_labeld.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_labeld # # Turn off labeld #. audit_labeld () { print_function "audit_labeld" string="Label Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/system/labeld:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_ncs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ncs # # Check NCS # # Refer to Section(s) 2.12.3 Page(s) 208 CIS AIX Benchmark v1.1.0 #. audit_ncs () { print_function "audit_ncs" string="NCS" check_message "${string}" if [ "${os_name}" = "AIX" ]; then check_itab "ncs" "off" else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_ndd_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ndd_value # # Modify Network Parameters # Checks and sets ndd values #. audit_ndd_value () { print_function "audit_ndd_value" string="NDD Value" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then ndd_name="${1}" ndd_property="${2}" correct_value="${3}" if [ "${ndd_property}" = "tcp_extra_priv_ports_add" ]; then command="ndd -get \"${ndd_name}\" tcp_extra_priv_ports | grep \"${correct_value}\"" command_message "${command}" current_value=$( eval "${command}" ) else command="ndd -get \"${ndd_name}\" \"${ndd_property}\"" command_message "${command}" current_value=$( eval "${command}" ) fi file_header="ndd" log_file="${work_dir}/${file_header}.log" if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${file_header}.log" if [ -f "${restore_file}" ]; then restore_property=$( grep "${ndd_property}," "${restore_file}" | cut -f2 -d',' ) restore_value=$( grep "${ndd_property}," "${restore_file}" | cut -f3 -d',' ) if [ -n "${restore_value}" ]; then if [ "${ndd_property}" = "tcp_extra_priv_ports_add" ]; then command="ndd -get \"${ndd_name}\" tcp_extra_priv_ports | grep \"${restore_value}\"" command_message "${command}" current_value=$( eval "${command}" ) fi if [ -n "${current_value}" ]; then if [ "${current_value}" != "${restore_value}" ]; then if [ "${ndd_property}" = "tcp_extra_priv_ports_add" ]; then ndd_property="tcp_extra_priv_ports_del" fi fix_message "Restoring: \"${ndd_name}\" \"${ndd_property}\" to \"${restore_value}\"" command="ndd -set \"${ndd_name}\" \"${ndd_property}\" \"${restore_value}\"" command_message "${command}" eval "${command}" fi fi fi fi else verbose_message "NDD ${ndd_name} ${ndd_property}" fi if [ "${current_value}" -ne "${correct_value}" ]; then command_line="ndd -set ${ndd_name} ${ndd_property} ${correct_value}" command_message "${command_line}" if [ "${audit_mode}" = 1 ]; then inc_insecure "NDD \"${ndd_name} ${ndd_property}\" not set to \"${correct_value}\"" fix_message "${command_line}" else if [ "${audit_mode}" = 0 ]; then fix_message "NDD \"${ndd_name} ${ndd_property}\" to \"${correct_value}\"" echo "${ndd_name},${ndd_property},${correct_value}" >> "${log_file}" eval "${command_line}" fi fi else if [ "${audit_mode}" != 2 ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "NDD \"${ndd_name} ${ndd_property}\" already set to \"${correct_value}\"" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_network_connections.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_network_connections # # Auditing of Incoming Network Connections #. audit_network_connections () { print_function "audit_network_connections" string="Auditing of Incomming Network Connections" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "11" ]; then check_append_file "/etc/security/audit_event" "lck:AUE_ACCEPT" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_CONNECT" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SOCKACCEPT" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SOCKCONNECT" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_inetd_connect" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_ocfserv.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ocfserv # # Turn off ocfserv #. audit_ocfserv () { print_function "audit_ocfserv" string="OCF Service" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/rpc/ocfserv:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_online_documentation.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_online_documentation # # Check online documentation daemon settings # # Refer to Section(s) 2.12.4 Page(s) 209 CIS AIX Benchmark v1.1.0 #. audit_online_documentation () { print_function "audit_online_documentation" string="Online Documentation" check_message "${string}" if [ "${os_name}" = "AIX" ] || [ "${os_name}" = "SunOS" ]; then if [ "${os_name}" = "AIX" ]; then check_itab "httpdlite" "off" fi if [ "${os_name}" = "SunOS" ]; then check_initd_service "ab2mgr" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_privilege_events.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_privilege_events # # Auditing of Process and Privilege Events # # Refer to Section(s) 4.4 Page(s) 43-44 CIS Solaris 11.1 Benchmark v1.0.0 #. audit_privilege_events () { print_function "audit_privilege_events" string="Auditing of Privileged Events" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "11" ]; then check_append_file "/etc/security/audit_event" "lck:AUE_CHROOT" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SETREUID" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SETREGID" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_FCHROOT" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_PFEXEC" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SETUID" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_NICE" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SETGID" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_PRIOCNTLSYS" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SETEGID" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SETEUID" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SETPPRIV" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SETSID" "hash" check_append_file "/etc/security/audit_event" "lck:AUE_SETPGID" "hash" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_service_tags.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_service_tags # # Turn off Service Tags if not being used. It can provide information that can # be used as vector of attack. #. audit_service_tags () { print_function "audit_service_tags" string="Service Tags" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/stdiscover:default" "disabled" check_sunos_service "svc:/network/stlisten:default" "disabled" check_sunos_service "svc:/application/stosreg:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_slp.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_slp # # Turn off slp #. audit_slp () { print_function "audit_slp" string="SLP Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/slp:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_solaris_auditing.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2154 # audit_solaris_auditing # # Check auditing setup on Solaris 11 # Need to investigate more auditing capabilities on Solaris 10 #. audit_solaris_auditing () { print_function "audit_solaris_auditing" string="Solaris Auditing" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "11" ]; then check_command_output "getcond" check_command_output "getpolicy" check_command_output "getnaflags" check_command_output "getplugin" check_command_output "userattr" if [ "${audit_mode}" != 1 ]; then audit -s fi check_file="/var/spool/cron/crontabs/root" if [ "${audit_mode}" = 0 ]; then log_file="$workdir${check_file}" rolemod -K audit_flags=lo,ad,ft,ex,lck:no root if [ -f "${check_file}" ]; then command="grep \"audit -n\" \"${check_file}\" | cut -f4 -d'/'" command_message "${command}" audit_check=$( eval "${command}" ) if [ "$audit_check" != "audit -n" ]; then if [ ! -f "${log_file}" ]; then verbose_message "File ${check_file} to ${work_dir}${check_file}" "save" command="find \"${check_file}\" | cpio -pdm \"${work_dir}\" 2> /dev/null" command_message "${command}" eval "${command}" fi command="echo \"0 * * * * /usr/sbin/audit -n\" >> \"${check_file}\"" command_message "${command}" eval "${command}" command="chown root:root /var/audit" command_message "${command}" eval "${command}" command="chmod 750 /var/audit" command_message "${command}" eval "${command}" command="pkg fix $( pkg search \"${check_file}\" | grep pkg | awk '{print \$4}' )" command_message "${command}" eval "${command}" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_stack_protection.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_stack_protection # # Check Stack Protection # # Checks for the following values in /etc/system: # # set noexec_user_stack=1 # set noexec_user_stack_log=1 # # Refer to Section(s) 3.2 Page(s) 26-7 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 3.3 Page(s) 62-3 CIS Solaris 10 Benchmark v5.1.0 #. audit_stack_protection () { print_function "audit_stack_protection" string="Stack Protection" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/system" "set noexec_user_stack" "eq" "1" "star" check_file_value "is" "/etc/system" "set noexec_user_stack_log" "eq" "1" "star" else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_svccfg_value.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_svccfg_value # # Check syscfg settings #. audit_svccfg_value () { print_function "audit_svccfg_value" string="RPC Port Mapping" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then service_name="${1}" service_property="${2}" correct_value="${3}" command="svccfg -s \"${service_name}\" listprop \"${service_property}\" | awk '{print \$3}'" command_message "${command}" current_value=$( eval "${command}" ) file_header="svccfg" log_file="${work_dir}/${file_header}.log" if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${file_header}.log" if [ -f "${restore_file}" ]; then command="grep \"${service_name}\" \"${restore_file}\" | cut -f2 -d','" command_message "${command}" restore_property=$( eval "${command}" ) command="grep \"${service_name}\" \"${restore_file}\" | cut -f3 -d','" command_message "${command}" restore_value=$( eval "${command}" ) command="expr \"${restore_property}\" : \"[A-z]\"" command_message "${command}" restore_check=$( eval "${command}" ) if [ "${restore_check}" = "1" ]; then if [ "${current_value}" != "${restore_value}" ]; then restore_message="Service \"${service_name}\" Property \"${restore_property}\" to \"${restore_value}\"" restore_command="svccfg -s ${service_name} setprop ${restore_property} = ${restore_value}" command_message "${restore_command}" execute_restore "${restore_command}" "${restore_message}" "sudo" fi fi fi else verbose_message "Service ${service_name}" fi if [ "${current_value}" != "${correct_value}" ]; then lock_command="svccfg -s ${service_name} setprop ${service_property} = ${correct_value}" if [ "${audit_mode}" = 1 ]; then inc_insecure "Service \"${service_name}\" Property \"${service_property}\" not set to \"${correct_value}\"" fix_message "${lock_command}" else if [ "${audit_mode}" = 0 ]; then update_log "${log_file}" "${service_name},${service_property},${current_value}" lock_message="${service_name} ${service_property} to ${correct_value}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi else if [ "${audit_mode}" != 2 ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "Service \"${service_name}\" Property \"${service_property}\" already set to \"${correct_value}\"" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_svm.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_svm # # Check volume manager daemons disabled # # Refer to Section(s) 2.2.8,12 Page(s) 28,32-3 CIS Solaris 10 Benchmark v5.1.0 #. audit_svm () { print_function "audit_svm" string="Solaris Volume Manager Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/system/metainit" "disabled" check_sunos_service "svc:/system/mdmonitor" "disabled" if [ "${os_update}" -lt 4 ]; then check_sunos_service "svc:/platform/sun4u/mpxio-upgrade" "disabled" else check_sunos_service "svc:/system/device/mpxio-upgrade" "disabled" fi fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_svm_gui.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_svm_gui # # Check Solaris Volume Manager GUI daemons disabled # # Refer to Section(s) 2.2.13 Page(s) 33-4 CIS Solaris 10 Benchmark v5.1.0 #. audit_svm_gui () { print_function "audit_svm_gui" string="Solaris Volume Manager GUI Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/network/rpc/mdcomm" "disabled" check_sunos_service "svc:/network/rpc/meta" "disabled" check_sunos_service "svc:/network/rpc/metamed" "disabled" check_sunos_service "svc:/network/rpc/metamh" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_ticotsord.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_ticotsord # # Turn off ticotsord #. audit_ticotsord () { print_function "audit_ticotsord" string="Ticotsord Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/rpc-100235_1/rpc_ticotsord:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_tname.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_tname # # Turn off tname #. audit_tname () { print_function "audit_tname" string="Tname Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/tname:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_tnd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_tnd # # Turn off tnd #. audit_tnd () { print_function "audit_tnd" string="TN Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/tnd:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_uucp.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_uucp # # Turn off uucp and swat #. audit_uucp () { print_function "audit_uucp" string="UUCP Service" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then verbose_message "Samba Web Configuration Deamon" "check" check_sunos_service "svc:/network/swat:defaulte" "disabled" fi if [ "${os_version}" = "10" ]; then verbose_message "UUCP Service" "check" check_sunos_service "uucp" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_vnetd.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_vnetd # # VNET Daemon # # Turn off vnetd #. audit_vnetd () { print_function "audit_vnetd" string="VNET Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/vnetd/tcp:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_volfs.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_volfs # # Refer to Section(s) 2.8 Page(s) 20-1 CIS Solaris 11.1 Benchmark v1.0.0 #. audit_volfs () { print_function "audit_volfs" string="Volume Management Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/system/filesystem/volfs" "disabled" fi if [ "${os_version}" = "11" ]; then check_sunos_service "svc:/system/filesystem/rmvolmgr" "disabled" fi if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/rpc/smserver" "disabled" fi if [ "${os_version}" = "10" ]; then check_sunos_service "volmgt" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_vopied.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_vopied # # Veritas Online Passwords In Everything # # Turn off vopied if not required. It is associated with Symantec products. #. audit_vopied () { print_function "audit_vopied" string="VOPIE Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/vopied/tcp:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_wbem.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_wbem # # Turn off Web Based Enterprise Management # # Refer to Section(s) 2.1.6 Page(s) 21-2 CIS Solaris 10 Benchmark v5.1.0 #. audit_wbem () { print_function "audit_wbem" string="Web Based Enterprise Management" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/application/management/wbem" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_webconsole.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_webconsole # # Turn of Web Console service # # Refer to Section(s) 2.1.5 Page(s) 20-1 CIS Solaris 10 Benchmark v5.1.0 #. audit_webconsole () { print_function "audit_webconsole" string="Web Console" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then check_sunos_service "svc:/system/webconsole:console" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_webmin.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_webmin # # Turn off webmin if it is not being used. #. audit_webmin () { print_function "audit_webmin" string="Webmin Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/application/management/webmin:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_wins.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_wins # # Turn off wins if not required #. audit_wins () { print_function "audit_wins" string="WINS Daemon" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then check_sunos_service "svc:/network/wins:default" "disabled" fi else na_message "${string}" fi } ================================================ FILE: modules/sunos/audit_zones.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_zones # # Turn off Zone services if zones are not being used. #. audit_zones () { print_function "audit_zones" string="Zone Daemons" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then zone_check=$( zoneadm list -civ | awk '{print $1}' | grep 1 ) if [ "${zone_check}" != "1" ]; then check_sunos_service "svc:/system/rcap:default" "disabled" check_sunos_service "svc:/system/pools:default" "disabled" check_sunos_service "svc:/system/tsol-zones:default" "disabled" check_sunos_service "svc:/system/zones:default" "disabled" fi fi else na_message "${string}" fi } ================================================ FILE: modules/syslog/audit_syslog_auth.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_syslog_auth # # Check auth log # # Refer to Section(s) 4.4 Page(s) 68-9 CIS Solaris 10 Benchmark v5.1.0 #. audit_syslog_auth () { print_function "audit_syslog_auth" string="SYSLOG AUTH Messages" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then audit_logadm_value "authlog" "auth.info" fi else na_message "${string}" fi } ================================================ FILE: modules/syslog/audit_syslog_conf.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_syslog_conf # # Check syslog confg # # Refer to Section(s) 3.4 Page(s) 10 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 5.1.1 Page(s) 104-5 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 1.11.13 Page(s) 39-40 CIS ESX Server 4 Benchmark v1.1.0 # # Refer to http://kb.vmware.com/kb/1033696 # Refer to http://pubs.vmware.com/vsphere-55/topic/com.vmware.vsphere.security.doc/GUID-9F67DB52-F469-451F-B6C8-DAE8D95976E7.html #. audit_syslog_conf () { print_function "audit_syslog_conf" string="Syslog Configuration" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "VMkernel" ]; then if [ "${os_name}" = "Linux" ]; then check_file="/etc/syslog.conf" if [ -f "/etc/rsyslog.conf" ]; then systemd_check=$(command -v systemctl 2> /dev/null ) if [ -n "$systemd_check" ]; then command="sudo systemctl | grep rsyslog | grep active | awk '{print \$1}'" command_message "${command}" rsyslog_check=$( eval "${command}" ) if [ "$rsyslog_check" = "rsyslog.service" ]; then if [ -f "/etc/rsyslog.d/90-cis.conf" ]; then check_file="/etc/rsyslog.d/90-cis.conf" else check_file="/etc/rsyslog.conf" fi fi fi fi check_file_value "is" "${check_file}" "authpriv.*" "tab" "/var/log/secure" "hash" check_file_value "is" "${check_file}" "auth.*" "tab" "/var/log/messages" "hash" check_file_value "is" "${check_file}" "daemon.*" "tab" "/var/log/daemon.log" "hash" check_file_value "is" "${check_file}" "syslog.*" "tab" "/var/log/syslog" "hash" check_file_value "is" "${check_file}" "lpr,news,uucp,local0,local1,local2,local3,local4,local5,local6.*" "tab" "/var/log/unused.log" "hash" fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/rc.conf" "syslogd_flags" "eq" "-s" "hash" fi if [ "${os_name}" = "VMkernel" ]; then log_file="sysloglogdir" backup_file="${work_dir}/${log_file}" command="esxcli system syslog config get | grep 'Local Log Output:' | awk '{print \$4}'" command_message "${command}" current_value=$( eval "${command}" ) if [ "${audit_mode}" != "2" ]; then if [ "${current_value}" = "/scratch/log" ]; then if [ "${audit_mode}" = "0" ]; then if [ "${syslog_logdir}" != "" ]; then echo "${current_value}" > "${backup_file}" verbose_message "Setting: Syslog log directory to a persistent datastore" esxcli system syslog config set --logdir="${syslog_logdir}" fi fi if [ "${audit_mode}" = "1" ]; then inc_insecure "Syslog log directory is not persistent" if [ "${syslog_logdir}" != "" ]; then fix_message "esxcli system syslog config set --logdir=${syslog_logdir}" fi fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Syslog log directory is on a persistent datastore" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then previous_value=$( cat "${restore_file}" ) if [ "${previous_value}" != "${current_value}" ]; then verbose_message "Restoring: Syslog log directory to ${previous_value}" command="esxcli system syslog config set --logdir=\"${previous_value}\"" command_message "${command}" eval "${command}" fi fi fi log_file="syslogremotehost" backup_file="${work_dir}/${log_file}" command="esxcli system syslog config get | grep Remote | awk '{print \$3}'" command_message "${command}" current_value=$( eval "${command}" ) if [ "${audit_mode}" != "2" ]; then if [ "${current_value}" = "" ]; then if [ "${audit_mode}" = "0" ]; then if [ "${syslog_server}" != "" ]; then echo "${current_value}" > "${backup_file}" command="esxcli system syslog config set --loghost=\"${syslog_server}\"" command_message "${command}" eval "${command}" fi fi if [ "${audit_mode}" = "1" ]; then inc_insecure "Syslog remote host is not enabled" if [ "${syslog_server}" = "" ]; then fix_message "esxcli system syslog config set --loghost=XXX.XXX.XXX.XXX" else fix_message "esxcli system syslog config set --loghost=${syslog_server}" fi fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Syslog remote host is enabled" fi fi else restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then previous_value=$( cat "${restore_file}" ) if [ "${previous_value}" != "${current_value}" ]; then verbose_message "Restoring: Syslog loghost to \"${previous_value}\"" command="esxcli system syslog config set --loghost=\"${previous_value}\"" command_message "${command}" eval "${command}" fi fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/syslog/audit_syslog_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_syslog_perms # # Check syslog permissions # # Refer to Section(s) 11.7-8 Page(s) 146-7 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 5.1.2 Page(s) 105-6 CIS RHEL 5 Benchmark v2.1.0 #. audit_syslog_perms () { print_function "audit_syslog_perms" string="Syslog Permissions" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${os_name}" = "SunOS" ]; then check_file_perms "/var/log/syslog" "0600" "root" "sys" fi if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then check_file_perms "/var/log/secure" "0600" "root" "root" check_file_perms "/var/log/messages" "0600" "root" "root" check_file_perms "/var/log/daemon.log" "0600" "root" "root" check_file_perms "/var/log/unused.log" "0600" "root" "root" fi else na_message "${string}" fi } ================================================ FILE: modules/syslog/audit_syslog_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2063 # shellcheck disable=SC2154 # audit_syslog_server # # Check syslog server settings # # Refer to Section(s) 4.1.1-8 Page(s) 71-76 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 5.2.1-8 Page(s) 108-113 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 5.1.1-8 Page(s) 94-9 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 4.2.1.1-5 Page(s) 192-198 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 8.2.1-8 Page(s) 106-111 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 5.1 Page(s) 18 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 4.2.1.1-5 Page(s) 176-82 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 4.2.1.1-5 Page(s) 187-93 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 4.2.1.1-4.2.2.7 Page(s) 556-92 CIS Ubuntu 22.04 Benchmark v1.0.0 # Refer to Section(s) 6.1.1.1.1-6.1.3.7 Page(s) 728-86 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_syslog_server () { print_function "audit_syslog_server" string="Syslog Server" check_message "${string}" if [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${os_name}" = "FreeBSD" ]; then if [ "${os_version}" -lt 5 ]; then check_file_value "is" "/etc/syslog.conf" "daemon.debug" "tab" "/var/log/daemon.log" "hash" check_file_exists "/var/log/daemon.log" "file" "yes" funct_file_perms "/var/log/daemon.log" "600" "root" "${wheel_group}" fi fi if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "Ubuntu" ] && [ "${os_version}" -ge 22 ]; then check_linux_package "install" "systemd-journal-remote" if [ "${syslog_server}" != "" ]; then check_file_value "is" "/etc/systemd/journal-upload.conf" "URL" "eq" "${syslog_server}" "hash" fi check_file_value "is" "/etc/systemd/journal-upload.conf" "ServerKeyFile" "eq" "/etc/ssl/private/journal-upload.pem" "hash" check_file_value "is" "/etc/systemd/journal-upload.conf" "ServerCertificateFile" "eq" "/etc/ssl/certs/journal-upload.pem" "hash" check_file_value "is" "/etc/systemd/journal-upload.conf" "TrustedCertificateFile" "eq" "/etc/ssl/ca/trusted.pem" "hash" check_file_value "is" "/etc/systemd/journald.conf" "Compress" "eq" "yes" "hash" check_file_value "is" "/etc/systemd/journald.conf" "Storage" "eq" "persistent" "hash" check_file_value "is" "/etc/systemd/journald.conf" "ForwardToSyslog" "eq" "yes" "hash" check_file_value "is" "/etc/systemd/journald.conf" "SystemMaxUse" "eq" "1G" "hash" check_file_value "is" "/etc/systemd/journald.conf" "SystemKeepFree" "eq" "500M" "hash" check_file_value "is" "/etc/systemd/journald.conf" "RuntimeMaxUse" "eq" "200M" "hash" check_file_value "is" "/etc/systemd/journald.conf" "RuntimeKeepFree" "eq" "50M" "hash" check_file_value "is" "/etc/systemd/journald.conf" "MaxFileSec" "eq" "1month" "hash" check_linux_service "systemd-journal-upload.service" "on" check_linux_service "systemd-journal-remote.socket" "off" check_linux_service "systemd-journald.service" "on" conf_file="/usr/lib/tmpfiles.d/systemd.conf" if [ -f "/usr/lib/tmpfiles.d/systemd.conf" ]; then conf_file="/usr/lib/tmpfiles.d/systemd.conf" else if [ -f "/etc/tmpfiles.d/systemd.conf" ]; then conf_file="/etc/tmpfiles.d/systemd.conf" fi fi if [ -f "${conf_file}" ]; then check_file_perms "${conf_file}" "0640" "root" "root" check_file_value "is" "${conf_file}" "d /var/lib/private" "space" "root root -" "hash" check_file_value "is" "${conf_file}" "d /var/log/private" "space" "root root -" "hash" check_file_value "is" "${conf_file}" "d /var/cache/private" "space" "root root -" "hash" fi fi conf_file="/etc/rsyslog.conf" if [ ! -f "${conf_file}" ]; then if [ "${install_rsyslog}" = "yes" ]; then check_linux_service "syslog" "off" check_linux_package "install" "rsyslog" check_linux_service "rsyslog" "on" fi fi if [ -f "/etc/rsyslog.d/60-rsyslog.conf" ]; then conf_file="/etc/rsyslog.d/60-rsyslog.conf" check_file_value "is" "${conf_file}" "auth,authpriv.*" "tab" "/var/log/secure" "hash" check_file_value "is" "${conf_file}" "mail.*" "tab" "/var/log/mail" "hash" check_file_value "is" "${conf_file}" "cron.*" "tab" "/var/log/cron" "hash" check_file_value "is" "${conf_file}" "*.=warning;*.=err" "tab" "/var/log/warn" "hash" check_file_value "is" "${conf_file}" "*.crit" "tab" "/var/log/warn" "hash" check_file_value "is" "${conf_file}" "*.*;mail.none;news.none" "tab" "/var/log/messages" "hash" check_file_value "is" "${conf_file}" "local0,local1.*" "tab" "/var/log/localmessages" "hash" check_file_value "is" "${conf_file}" "local2,local3.*" "tab" "/var/log/localmessages" "hash" check_file_value "is" "${conf_file}" "local4,local5.*" "tab" "/var/log/localmessages" "hash" check_file_value "is" "${conf_file}" "local6,local1.*" "tab" "/var/log/localmessages" "hash" conf_file="/etc/rsyslog.d/50-default.conf" check_file_value "is" "${conf_file}" "auth,authpriv.*" "tab" "/var/log/auth.log" "hash" check_file_value "is" "${conf_file}" "*.*;auth,authpriv.*" "tab" "/var/log/syslog" "hash" check_file_value "is" "${conf_file}" "kern.*" "tab" "/var/log/kern.log" "hash" check_file_value "is" "${conf_file}" "mail.*" "tab" "/var/log/mail" "hash" else if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "SuSE" ] || [ "${os_vendor}" = "Amazon" ]; then if [ "${os_version}" -lt 4 ]; then check_file_value "is" "${conf_file}" "*.emerg" "tab" ":omusrmsg:*" "hash" check_file_value "is" "${conf_file}" "mail.*" "tab" "/var/log/mail" "hash" check_file_value "is" "${conf_file}" "cron.*" "tab" "/var/log/cron" "hash" check_file_value "is" "${conf_file}" "*.crit" "tab" "/var/log/warn" "hash" check_file_value "is" "${conf_file}" "kern.*" "tab" "/var/log/kern.log" "hash" check_file_value "is" "${conf_file}" "daemon.*" "tab" "/var/log/daemon.log" "hash" check_file_value "is" "${conf_file}" "syslog.*" "tab" "/var/log/syslog" "hash" check_file_value "is" "${conf_file}" "auth,user.*" "tab" "/var/log/auth.log" "hash" check_file_value "is" "${conf_file}" "auth,authpriv.*" "tab" "/var/log/secure" "hash" check_file_value "is" "${conf_file}" "*.=warning;*.=err" "tab" "/var/log/warn" "hash" check_file_value "is" "${conf_file}" "*.*;mail.none;news.none" "tab" "/var/log/messages" "hash" check_file_value "is" "${conf_file}" "lpr,news,uucp,local0,local1,local2,local3,local4,local5,local6.*" "tab" "/var/log/localmessages" "hash" funct_file_perms "${conf_file}" "0600" "root" "root" if [ "${audit_mode}" != 2 ]; then command="grep -v '#' \"${check_file}\" | grep \"*.* @@\" | grep -v localhost | grep -c \"[A-Z]|[a-z]\"" command_message "${command}" remote_check=$( eval "${command}" ) if [ "${remote_check}" != "1" ]; then if [ "${audit_mode}" = 1 ] || [ "${audit_mode}" = 0 ]; then inc_insecure "Rsyslog is not sending messages to a remote server" fix_message "Add a server entry to ${check_file}, eg:" fix_message "*.* @@loghost.example.com" fi else inc_secure "Rsyslog is sending messages to a remote server" fi fi fi fi fi conf_file="/etc/rsyslog.conf" if [ -f "${conf_file}" ]; then command="grep -E \"imtcp|imudp\" < \"${conf_file}\" | grep -cv \"^#\" | sed \"s/ //g\"" command_message "${command}" server_check=$( eval "${command}" ) if [ "${server_check}" = "0" ]; then inc_secure "Rsyslog is not running in server mode" else inc_insecure "Rsyslog is running in server mode" fi check_file_value "is" "${conf_file}" "\$FileCreateMode" "space" "0640" "hash" fi fi else na_message "${string}" fi } ================================================ FILE: modules/talk/audit_talk_client.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_talk_client # # Uninstall talk client # # Refer to Section(s) 2.1.9 Page(s) 53 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.9 Page(s) 61 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.9 Page(s) 55-6 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.3.3 Page(s) 126 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.2.6 Page(s) 43-4 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.3.3 Page(s) 113 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.3.3 Page(s) 122 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.2.3 Page(s) 296-7 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_talk_client () { print_function "audit_talk_client" string="Talk Client" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_linux_package "uninstall" "talk" else na_message "${string}" fi } ================================================ FILE: modules/talk/audit_talk_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_talk_server # # Turn off talk server # # Refer to Section(s) 2.1.10 Page(s) 53-54 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.10 Page(s) 61-2 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.10 Page(s) 56 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.1.18 Page(s) 119 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 5.1.5 Page(s) 43 CIS SLES 11 Benchmark v1.0.0 #. audit_talk_server () { print_function "audit_talk_server" string="Talk Server" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "Amazon" ]; then check_linux_service "ntalk" "off" check_linux_package "uninstall" "talk-server" fi else na_message "${string}" fi } ================================================ FILE: modules/tcp/audit_tcp_strong_iss.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_tcp_strong_iss # # Strong TCP Sequence Number Generation # # Checks for the following values in /etc/default/inetinit: # # TCP_STRONG_ISS=2 # # 0 = Old-fashioned sequential initial sequence number generation. # 1 = Improved sequential generation, with random variance in increment. # 2 = RFC 1948 sequence number generation, unique-per-connection-ID. # # Refer to Section(s) 3.3 Page(s) 27-8 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 3.4 Page(s) 63-4 CIS Solaris 10 Benchmark v5.1.0 #. audit_tcp_strong_iss () { print_function "audit_tcp_strong_iss" string="TCP Sequence Number Generation" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/default/inetinit" "TCP_STRONG_ISS" "eq" "2" "hash" if [ "${os_version}" != "11" ]; then audit_ndd_value "/dev/tcp" "tcp_strong_iss" "2" fi if [ "${os_version}" = "11" ]; then audit_ipadm_value "_strong_iss" "tcp" "2" fi else na_message "${string}" fi } ================================================ FILE: modules/tcp/audit_tcp_syn_cookie.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_tcpsyn_cookie # # TCP SYN Cookie Protection # # Refer to Section(s) 4.2.8 Page(s) 90-1 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 4.2.8 Page(s) 82-3 CIS RHEL 6 Benchmark v1.2.0 #. audit_tcp_syn_cookie () { print_function "audit_tcp_syn_cookie" string="TCP SYN Cookie Protection" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_append_file "/etc/rc.d/local" "echo 1 > /proc/sys/net/ipv4/tcp_syncookies" "hash" check_file_perms "/etc/rc.d/local" "0600" "root" "root" else na_message "${string}" fi } ================================================ FILE: modules/tcp/audit_tcp_wrappers.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2046 # shellcheck disable=SC2154 # audit_tcp_wrappers # # Check TCP wrappers # # Refer to Section(s) 5.5.1-5 Page(s) 110-114 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 4.5.1-5 Page(s) 95-8 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 4.5.1-5 Page(s) 86-9 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 3.4.1-5 Page(s) 143-8 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 7.4.1-5 Page(s) 77-80 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 1.3 Page(s) 3-4 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.10.1-4 Page(s) 188-192 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 2.11 Page(s) 22-3 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 2.4 Page(s) 36-7 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 3.4.1-5 Page(s) 1verbose_message "-4 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 3.4.1-5 Page(s) 139-43 CIS Ubuntu 16.04 Benchmark v2.0.0 #. audit_tcp_wrappers () { print_function "audit_tcp_wrappers" string="TCP Wrappers" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then package_name="netsec.options.tcpwrapper.base" check_lslpp "${package_name}" if [ "${audit_mode}" != 2 ]; then if [ "${lslpp_check}" != "${package_name}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "TCP Wrappers not installed" fix_message "TCP Wrappers not installed" fix_message "Install TCP Wrappers" fi else inc_secure "TCP Wrappers installed" fi fi fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ] || [ "${os_version}" = "11" ]; then audit_rpc_bind for service_name in $( inetadm | awk '{print $3}' | grep "^svc" ); do check_command_value "inetadm" "tcp_wrappers" "TRUE" "${service_name}" done fi fi if [ "${os_name}" = "FreeBSD" ]; then check_file_value "is" "/etc/rc.conf" "inetd_enable" "eq" "YES" "hash" check_file_value "is" "/etc/rc.conf" "inetd_flags" "eq" "-Wwl -C60" "hash" fi check_file_value "is" "/etc/hosts.deny" "ALL" "colon" " ALL" "hash" check_file_value "is" "/etc/hosts.allow" "ALL" "colon" " localhost" "hash" check_file_value "is" "/etc/hosts.allow" "ALL" "colon" " 127.0.0.1" "hash" ip_list=$( who | cut -d"(" -f2 | cut -d")" -f1 | sort -u ) for ip_address in ${ip_list}; do check_file_value "is" "/etc/hosts.allow" "ALL" "colon" " ${ip_address}" "hash" done if [ ! -f "${check_file}" ]; then check=$( command -v ifconfig 2> /dev/null ) if [ "${check}" ]; then command="ifconfig -a | grep 'inet [0-9]' | grep -v ' 127.' | awk '{print \$2}' | cut -f2 -d':'" command_message "${command}" ip_list=$( eval "${command}" ) for ip_address in ${ip_list}; do netmask=$( ifconfig -a | grep "${ip_address}" | awk '{print $3}' | cut -f2 -d:) for daemon in ${tcpd_allow}; do check_file_value "is" "${check_file}" "${daemon}" "colon" " ${ip_address}/${netmask}" "hash" done done else check=$( command -v ip 2> /dev/null ) if [ "${check}" ]; then command="ip addr | grep 'inet [0-9]' | grep -v ' 127.' | awk '{print \$2}'" command_message "${command}" ip_values=$( eval "${command}" ) for ip_value in $ip_values; do set -- $( echo "$ip_value" | awk -F"/" '{print $1" "$2 }' ) ip_address="${1}" cidr="${2}" netmask=$( cidr_to_mask "$cidr" ) for daemon in ${tcpd_allow}; do check_file_value "is" "${check_file}" "${daemon}" "colon" " ${ip_address}/${netmask}" "hash" done done fi fi fi if [ "${os_name}" = "AIX" ]; then group_name="system" else group_name="root" fi check_file_perms "/etc/hosts.deny" "0644" "root" "${group_name}" check_file_perms "/etc/hosts.allow" "0644" "root" "${group_name}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "Red" ] || [ "${os_vendor}" = "SuSE" ] || [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Amazon" ] ; then check_linux_package "install" "tcp_wrappers" else check_linux_package "install" "tcpd" fi fi else na_message "${string}" fi } ================================================ FILE: modules/telnet/audit_telnet_banner.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_telnet_banner # # Set telnet banner # # Refer to Section(s) 8.5 Page(s) 71 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 8.5 Page(s) 114-5 CIS Solaris 10 Benchmark v5.1.0 #. audit_telnet_banner () { print_function "audit_telnet_banner" string="Telnet Banner" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/default/telnetd" "BANNER" "eq" "/etc/issue" "hash" else na_message "${string}" fi } ================================================ FILE: modules/telnet/audit_telnet_client.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_telnet_client # # If telnet is not installed # # Refer to Section(s) 2.1.2 Page(s) 49 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.2 Page(s) 56 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.2 Page(s) 51 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.3.4 Page(s) 127 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 2.3.4 Page(s) 114 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 2.3.4 Page(s) 123 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 2.2.4 Page(s) 298-9 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_telnet_client () { print_function "audit_telnet_client" string="Telnet Client" check_message "${string}" if [ "${os_name}" = "Linux" ]; then check_linux_package "uninstall" "telnet" check_linux_package "uninstall" "inetutils-telnet" else na_message "${string}" fi } ================================================ FILE: modules/telnet/audit_telnet_server.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_telnet_server # # Turn off telner server # # Refer to Section(s) 2.1.1 Page(s) 47-48 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 2.1.1 Page(s) 55 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 2.1.1 Page(s) 50-1 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 2.1.1 Page(s) 55 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.1.7 Page(s) 44 CIS SLES 11 Benchmark v1.0.0 #. audit_telnet_server () { print_function "audit_telnet_server" string="Telnet Server" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${os_vendor}" = "CentOS" ] || [ "${os_vendor}" = "Red" ] || [ "${os_name}" = "Amazon" ]; then check_linux_service "telnet.socket" "off" check_linux_package "uninstall" "telnet-server" fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_daemon_umask.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_daemon_umask # # Check daemon umask # # Refer to Section(s) 3.1 Page(s) 58-9 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 3.2 Page(s) 72 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 3.1 Page(s) 61-2 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 3.3 Page(s) 9-10 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 5.1 Page(s) 75-6 CIS Solaris 10 Benchmark v5.1.0 #. audit_daemon_umask () { print_function "audit_daemon_umask" string="Daemon Umask" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "11" ]; then command="svcprop -p umask/umask svc:/system/environment:init" command_message "${command}" umask_check=$( eval "${command}" ) umask_value="022" log_file="umask.log" if [ "${umask_check}" != "${umask_value}" ]; then log_file="${work_dir}/${log_file}" if [ "${audit_mode}" = 1 ]; then inc_insecure "Default service file creation mask not set to ${umask_value}" verbose_message "svccfg -s svc:/system/environment:init setprop umask/umask = astring: \"${umask_value}\"" "fix" fi if [ "${audit_mode}" = 0 ]; then verbose_message "Setting: Default service file creation mask to ${umask_value}" if [ ! -f "${log_file}" ]; then echo "${umask_check}" >> "${log_file}" fi svccfg -s svc:/system/environment:init setprop umask/umask = astring: "${umask_value}" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Default service file creation mask set to ${umask_value}" fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/${log_file}" if [ -f "${restore_file}" ]; then restore_value=$( cat "${restore_file}" ) if [ "${restore_value}" != "${umask_check}" ]; then verbose_message "Restoring: Default service file creation mask to ${restore_value}" svccfg -s svc:/system/environment:init setprop umask/umask = astring: "${restore_value}" fi fi fi fi else if [ "${os_version}" = "7" ] || [ "${os_version}" = "6" ]; then check_file="/etc/init.d/umask.sh" check_file_value "is" "${check_file}" "umask" "space" "022" "hash" if [ "${audit_mode}" = "0" ]; then if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0744" "root" "sys" for dir_name in /etc/rc?.d; do link_file="${dir_name}/S00umask" if [ ! -f "$link_file" ]; then ln -s "${check_file}" "$link_file" fi done fi fi else check_file="/etc/default/init" check_file_value "is" "${check_file}" "CMASK" "eq" "022" "hash" fi fi fi if [ "${os_name}" = "Linux" ]; then check_file="/etc/sysconfig/init" check_file_value "is" "${check_file}" "umask" "space" "027" "hash" if [ "${audit_mode}" = "0" ]; then if [ -f "${check_file}" ]; then check_file_perms "${check_file}" "0755" "root" "root" fi fi fi # Check relevant /etc/* directoris for files with a potential umasks for dir_name in /etc /etc/rc0.d /etc/rc1.d /etc/rc2.d /etc/rc4.d /etc/rc5.d /etc/rcS.d /usr/local/etc; do if [ -e "${dir_name}" ]; then file_list=$( find /etc/ -maxdepth 1 -type f ) for check_file in ${file_list}; do umask_test=$( grep -c "umask" "${check_file}" | sed "s/ //g" ) if [ ! "$umask_test" = "0" ]; then check_file_value "is" "${check_file}" "umask" "space" "077" "hash" fi done fi done else na_message "${string}" fi } ================================================ FILE: modules/users/audit_default_umask.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_default_umask # # Check default umask # # Refer to Section(s) 7.4 Page(s) 147-8 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 7.4 Page(s) 170-1 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 7.4 Page(s) 150-1 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.4.4 Page(s) 254-5 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 10.4 Page(s) 140 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 8.8 Page(s) 29 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 7.3 Page(s) 64-5 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 7.6 Page(s) 106-7 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 5.4.4 Page(s) 233-4 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 5.4.4 Page(s) 246-7 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 5.4.2.6,5.4.3.3 Page(s) 705-7,719-25 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_default_umask () { print_function "audit_default_umask" string="Default umask for Users" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/etc/default/login" "UMASK" "eq" "077" "hash" fi if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then for check_file in /etc/.login /etc/profile /etc/skel/.bash_profile /etc/csh.login \ /etc/csh.cshrc /etc/zprofile /etc/skel/.zshrc /etc/skel/.bashrc; do check_file_value "is" "${check_file}" "umask" "space" "077" "hash" done for check_file in /etc/bashrc /etc/skel/.bashrc /etc/login.defs; do check_file_value "is" "${check_file}" "UMASK" "eq" "077" "hash" done fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_dot_files.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_dot_files # # Check for a dot file and copy it to backup directory #. audit_dot_files () { print_function "audit_dot_files" string="Dot Files" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then check_file="${1}" if [ "${audit_mode}" != 2 ]; then dir_list=$( cut -f6 -d':' /etc/passwd ) for dir_name in ${dir_list}; do if [ "${dir_name}" = "/" ]; then dot_file="/${check_file}" else dot_file="${dir_name}/${check_file}" fi if [ -f "${dot_file}" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "File \"${dot_file}\" ${exists}" fix_message "mv ${dot_file} ${dot_file}.disabled" fi if [ "${audit_mode}" = 0 ];then backup_file "${dot_file}" fi else if [ "${audit_mode}" = 1 ];then inc_secure "File \"${dot_file}\" does not exist" fi fi done else file_list=$( find "${restore_dir}" -name "${check_file}" ) for check_file in ${file_list}; do restore_file "${check_file}" "${restore_dir}" done fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_duplicate_ids.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_duplicate_ids # # Code to check for duplicate IDs # Routine to check a file for duplicates # Takes: # field: Field number # function: String describing action, eg users # term: String describing term, eg name # check_file: File to parse # # Although the useradd program will not let you create a duplicate User ID # (UID), it is possible for an administrator to manually edit the /etc/passwd # file and change the UID field. # #. audit_duplicate_ids () { print_function "audit_duplicate_ids" string="Duplicate IDs" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then field_no="${1}" function="${2}" term="${3}" check_file="${4}" duplicate=0 if [ "${audit_mode}" != 2 ]; then file_list=$( cut -f"${field_no}" -d: < "${check_file}" | sort -n | uniq -c | awk '{ print $1":"$2 }' ) for file_info in ${file_list}; do file_check=$( expr "${file_info}" : "[A-z,0-9]" ) if [ "${file_check}" = 1 ]; then file_check=$( expr "${file_info}" : "2" ) if [ "${file_check}" = 1 ]; then file_id=$( echo "${file_info}" |cut -f2 -d:) if [ "${audit_mode}" = 1 ];then inc_insecure "There are multiple \"${function}\" with \"${term}\" \"${file_id}\"" duplicate=1 fi fi fi done if [ "${audit_mode}" = 1 ]; then if [ "${duplicate}" = 0 ];then inc_secure "No \"${function}\" with duplicate \"${term}\"" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_duplicate_users.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_duplicate_users # # Check duplicate users # # Refer to Section(s) 9.2.16,17 Page(s) 174-5 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.15,18 Page(s) 201,203-4 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.16,17 Page(s) 177-8 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.2.16,18 Page(s) 291,3 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 13.14,16 Page(s) 164-5 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.12.16 Page(s) 219 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9.15,18 Page(s) 82-3,5 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.15,18 Page(s) 128-9,131 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.16,18 Page(s) 269,71 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.16,18 Page(s) 283,5 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 7.2.5,7 Page(s) 977-8,974-5 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_duplicate_users () { print_function "audit_duplicate_users" string="Duplicate Users" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "AIX" ]; then audit_duplicate_ids "1" "users" "name" "/etc/passwd" audit_duplicate_ids "3" "users" "id" "/etc/passwd" else na_message "${string}" fi } ================================================ FILE: modules/users/audit_forward_files.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_forward_files # # Check dot forward files # # Refer to Section(s) 9.2.19 Page(s) 176-7 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.21 Page(s) 206-7 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.20 Page(s) 180-1 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.2.11 Page(s) 2815 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 13.19 Page(s) 167-8 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 9.21 Page(s) 87 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.21 Page(s) 133-4 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.11 Page(s) 263 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.11 Page(s) 277 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_forward_files () { print_function "audit_forward_files" string="User Forward Files" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then audit_dot_files ".forward" else na_message "${string}" fi } ================================================ FILE: modules/users/audit_home_ownership.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2012 # shellcheck disable=SC2030 # shellcheck disable=SC2031 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_home_ownership # # Check home ownership # # Bug: insecure_count is being reset to 0 # # Refer to Section(s) 9.2.7,12,3 Page(s) 166-7,171-2 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.7,12-4 Page(s) 192-3,197-200 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.7,12-4 Page(s) 170,174-6 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.2.7,9 Page(s) 281,3 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 13.12-3 Page(s) 162-3 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.11.18-20 Page(s) 202-6 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9.12-4 Page(s) 80-1 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.12-4 Page(s) 126-8 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.7,9 Page(s) 259,61 CIS Amazon Linux Benchmark v1.0.0 # Refer to Section(s) 6.2.7,9 Page(s) 273,5 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 7.2.9 Page(s) 981-5 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_home_ownership () { print_function "audit_home_ownership" string="Ownership of Home Directories" check_message "${string}" found=0 if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then if [ "${audit_mode}" != 2 ]; then command="lsuser -c ALL | grep -v \"^#name\" | cut -f1 -d:" command_message "${command}" lsuser -c ALL | grep -v "^#name" | cut -f1 -d: | while read -r check_user; do user_check=$( lsuser -f "${check_user}" | grep id | cut -f2 -d= ) if [ "${user_check}" -ge 200 ]; then found=0 command="lsuser -a home \"${check_user}\" | cut -f2 -d=" command_message "${command}" home_dir=$( eval "${command}" ) else found=1 fi if [ "${found}" = 0 ]; then if [ -z "${home_dir}" ] || [ "${home_dir}" = "/" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "User \"${check_user}\" has no home directory defined" fi else if [ -d "${home_dir}" ]; then command="ls -ld \"${home_dir}/.\" | awk '{ print \$3 }'" command_message "${command}" dir_owner=$( eval "${command}" ) if [ "${dir_owner}" != "${check_user}" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "Home Directory for \"${check_user}\" is owned by \"${dir_owner}\"" fi else if [ -z "${home_dir}" ] || [ "${home_dir}" = "/" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "User \"${check_user}\" has no home directory" fi fi fi fi fi fi done fi fi if [ "${os_name}" = "SunOS" ]; then if [ "${audit_mode}" != 2 ]; then getent passwd | awk -F: '{ print $1" "$6 }' | while read -r check_user home_dir; do found=0 for test_user in root daemon bin sys adm lp uucp nuucp smmsp listen \ gdm webservd postgres svctag nobody noaccess nobody4 unknown; do if [ "${check_user}" = "${test_user}" ]; then found=1 fi done if [ "${found}" = 0 ]; then if [ -z "${home_dir}" ] || [ "${home_dir}" = "/" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "User \"${check_user}\" has no home directory defined" fi else if [ -d "${home_dir}" ]; then command="ls -ld \"${home_dir}/.\" | awk '{ print \$3 }'" command_message "${command}" dir_owner=$( eval "${command}" ) if [ "${dir_owner}" != "${check_user}" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "Home Directory for \"${check_user}\" is owned by \"${dir_owner}\"" fi else if [ -z "${home_dir}" ] || [ "${home_dir}" = "/" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "User \"${check_user}\" has no home directory" fi fi fi fi fi fi done fi fi if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then getent passwd | awk -F: '{ print $1" "$6 }' | while read -r check_user home_dir; do found=0 for test_user in root bin daemon adm lp sync shutdown halt mail news uucp \ operator games gopher ftp nobody nscd vcsa rpc mailnull smmsp pcap \ dbus sshd rpcuser nfsnobody haldaemon distcache apache \ oprofile webalizer dovecot squid named xfs gdm sabayon; do if [ "${check_user}" = "${test_user}" ]; then found=1 fi done if [ "${found}" = 0 ]; then if test -r "${home_dir}"; then if [ -z "${home_dir}" ] || [ "${home_dir}" = "/" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "User \"${check_user}\" has no home directory defined" fi else if [ -d "${home_dir}" ]; then command="ls -ld \"${home_dir}/.\" | awk '{ print \$3 }'" command_message "${command}" dir_owner=$( eval "${command}" ) if [ "${dir_owner}" != "${check_user}" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "Home Directory for \"${check_user}\" is owned by \"${dir_owner}\"" fi else if [ -z "${home_dir}" ] || [ "${home_dir}" = "/" ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "User \"${check_user}\" has no home directory" fi fi fi fi fi fi fi done fi fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_home_perms.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_home_perms # # Check home permissions # # Refer to Section(s) 5.4 Page(s) 51-52 CIS Apple OS X 10.8 Benchmark v1.0.0 # Refer to Section(s) 6.6 Page(s) 22 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 13.7 Page(s) 158-9 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 9.7 Page(s) 77 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.7 Page(s) 121 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.8 Page(s) 282 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 6.2.8 Page(s) 260 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.8 Page(s) 274 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 5.1.1 Page(s) 107-8 CIS Apple OS X 10.12 Benchmark v1.0.0 # Refer to Section(s) 5.1.1 Page(s) 298-9 CIS Apple macOS 14 Sonoma Benchmark v1.0.0 #. audit_home_perms () { print_function "audit_home_perms" string="Home Directory Permissions" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ] || [ "${os_name}" = "FreeBSD" ]; then if [ "${do_fs}" = "1" ]; then command="cut -f6 -d: < /etc/passwd | grep -v \"^#\" | grep -v \"^/\$\" | egrep -iE \"home|users\"" command_message "${command}" dir_list=$( eval "${command}" ) for home_dir in ${dir_list}; do if [ -d "${home_dir}" ]; then check_file_perms "${home_dir}" "0700" fi done if [ "${os_name}" = "Darwin" ]; then command="find /Users -maxdepth 1 | grep -vE \"localized|Shared\" | cut -f3 -d/" command_message "${command}" dir_list=$( eval "${command}" ) for home_dir in ${dir_list}; do check_file_perms "/Users/${home_dir}" "0700" done fi fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_inactive_users.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_inactive_users # # Check inactive users # # Refer to Section(s) 7.5 Page(s) 171-2 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 7.5 Page(s) 151-2 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 10.5 Page(s) 141 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 7.6 Page(s) 66-7 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 7.9 Page(s) 109-110 CIS Solaris 10 Benchmark v5.1.0 #. audit_inactive_users () { print_function "audit_inactive_users" string="Inactive User Accounts" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi if [ "${os_name}" = "SunOS" ]; then check_file_value "is" "/usr/sadm/defadduser" "definact" "eq" "35" "hash" fi check_file="/etc/shadow" if test -r "${check_file}"; then if [ "${audit_mode}" != 2 ]; then command="grep -v nobody4 < ${check_file} | grep -v root" command_message "${command}" user_list=$( eval "${command}" ) for user_check in ${user_list}; do command="echo \"${user_check}\" | cut -f 7 -d:" command_message "${command}" inactive=$( eval "${command}" ) command="echo \"${user_check}\" | cut -f 1 -d:" command_message "${command}" user_name=$( eval "${command}" ) if [ "$inactive" = "" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Inactive lockout not set for \"${user_name}\"" fix_message "usermod -f 35 ${user_name}" fi if [ "${audit_mode}" = 0 ]; then verbose_message "File \"${check_file}\" to \"${work_dir}${check_file}\"" "save" command="find \"${check_file}\" | cpio -pdm \"${work_dir}\" 2> /dev/null" command_message "${command}" eval "${command}" set_message "Inactive lockout for \"${user_name}\"" command="usermod -f 35 \"${user_name}\"" command_message "${command}" eval "${command}" fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Inactive lockout set for user \"${user_name}\"" fi fi done else restore_file "${check_file}" "${restore_dir}" fi fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_mesgn.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_mesgn # # Check mesgn set in profiles # # Refer to Section(s) 8.9 Page(s) 29 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 2.12.7 Page(s) 211-2 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 7.5 Page(s) 66 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 7.8 Page(s) 108-9 CIS Solaris 10 Benchmark v5.1.0 #. audit_mesgn () { print_function "audit_mesgn" string="Messages are disabled by default" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then for check_file in /etc/.login /etc/profile /etc/skel/.bash_profile /etc/skel/.bashrc \ /etc/csh.login /etc/csh.cshrc /etc/zprofile /etc/skel/.zshrc /etc/skel/.bashrc; do check_file_value "is" "${check_file}" "mesg" "space" "n" "hash" done else na_message "${string}" fi } ================================================ FILE: modules/users/audit_netrc_files.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_netrc_files # # Check netrc files # # Refer to Section(s) 6.2.12-3 Page(s) 264-6 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.12-3 Page(s) 278-80 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_netrc_files () { print_function "audit_netrc_files" string="Netrc Files" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then audit_dot_files ".netrc" else na_message "${string}" fi } ================================================ FILE: modules/users/audit_old_users.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_old_users # # Audit users to check for accounts that have not been logged into etc #. audit_old_users () { print_function "audit_old_users" string="Old Users" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi last_test=$( command -v last) if [ "${last_test}" = "" ]; then inc_insecure "last command not found" fix_message "Install wtmpdb package" return fi never_count=0 if [ "${audit_mode}" = 2 ]; then restore_file "/etc/shadow" "${restore_dir}" else command="grep -v \"/usr/bin/false\" \"/etc/passwd\" | grep -Ev \"^halt|^shutdown|^root|^sync|/sbin/nologin\" | cut -f1 -d:" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do if test -r "/etc/shadow"; then command="grep \"^${user_name}:\" \"/etc/shadow\" | cut -f2 -d: | grep -cEv \"\*|\!\!|NP|LK|UP\" | sed \"s/ //g\"" command_message "${command}" shadow_check=$( eval "${command}" ) if [ "$shadow_check" = "1" ]; then command="last \"${user_name}\" | awk '{print \$1}' | grep -c \"${user_name}\" | sed \"s/ //g\"" command_message "${command}" login_check=$( eval "${command}" ) if [ "$login_check" = "1" ]; then if [ "${audit_mode}" = 1 ]; then never_count=$((never_count+1)) inc_insecure "User \"${user_name}\" has not logged in recently and their account is not locked" fix_message "passwd -l ${user_name}" fi if [ "${audit_mode}" = 0 ]; then backup_file "/etc/shadow" set_message "User \"${user_name}\" to locked" passwd -l "${user_name}" fi fi fi fi done if [ "${never_count}" = 0 ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "There are no users who have never logged that do not have their account locked" fi fi fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_reserved_ids.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_reserved_ids # # Check reserved IDs # # Bug: sets insecure_count to 0 for some reason # # Refer to Section(s) 9.2.17 Page(s) 202-3 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.17 Page(s) 84-5 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.17 Page(s) 130-1 CIS Solaris 10 Benchmark v1.1.0 #. audit_reserved_ids () { print_function "audit_reserved_ids" string="Reserved IDs" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${audit_mode}" != 2 ]; then command="getent passwd | awk -F: '(\$3 < 500) { print \"\$1\" \"\$3\" }'" command_message "${command}" getent passwd | awk -F: '($3 < 100) { print $1" "$3 }' | while read -r check_user check_uid; do found=0 for test_user in root daemon bin sys adm lp uucp nuucp smmsp listen \ gdm webservd postgres svctag nobody noaccess nobody4 unknown; do if [ "${check_user}" = "${test_user}" ]; then found=1 fi done if [ "${found}" = 0 ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "User \"${check_user}\" has a reserved UID \"${check_uid}\"" fi fi done fi else if [ "${os_name}" = "Linux" ]; then if [ "${audit_mode}" != 2 ]; then check_message "Reserved UUIDs are assigned to system accounts" fi if [ "${audit_mode}" != 2 ]; then command="getent passwd | awk -F: '(\$3 < 500) { print \"\$1\" \"\$3\" }'" command_message "${command}" getent passwd | awk -F: '($3 < 500) { print $1" "$3 }' | while read -r check_user check_uid; do found=0 for test_user in root bin daemon adm lp sync shutdown halt mail news uucp \ operator games gopher ftp nobody nscd vcsa rpc mailnull smmsp pcap \ dbus sshd rpcuser nfsnobody haldaemon distcache apache \ oprofile webalizer dovecot squid named xfs gdm sabayon; do if [ "${check_user}" = "${test_user}" ]; then found=1 fi done if [ "${found}" = 0 ]; then if [ "${audit_mode}" = 1 ];then inc_insecure "User \"${check_user}\" has a reserved UID \"${check_uid}\"" fi fi done fi else na_message "${string}" fi fi } ================================================ FILE: modules/users/audit_rhosts_files.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_rhosts_files # # Check rhosts files # # Refer to Section(s) 1.5.2 Page(s) 102-3 CIS AIX Benchmark v1.1.0 #. audit_rhosts_files () { print_function "audit_rhosts_files" string="Rhosts Files" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "AIX" ] || [ "${os_name}" = "Linux" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then notice_message "Requires sudo to check" return fi for check_file in /.rhosts /.shosts /root/.rhosts /root/.shosts /etc/hosts.equiv; do check_file_exists "${check_file}" "no" done else na_message "${string}" fi } ================================================ FILE: modules/users/audit_root_access.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_root_access # # Check root access # # Refer to Section(s) 7.5 Page(s) 105-6 CIS Solaris 10 Benchmark v5.1.0 # Refer to Section(s) 5.4.2.4 Page(s) 700-1 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_root_access () { print_function "audit_root_access" string="Root Access" check_message "${string}" if [ "${os_name}" = "Linux" ]; then if [ "${my_id}" != "0" ] && [ "${use_sudo}" = "0" ]; then verbose_message "Requires sudo to check" "notice" return fi access_test=$( passwd -S root | awk '{ print $2}' | grep -cE "L" ) if [ "${access_test}" = "0" ]; then inc_insecure "Root account is not locked" else inc_secure "Root account is locked" fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_root_home.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_root_home # # Check root home # # Refer to Section(s) 7.5 Page(s) 105-6 CIS Solaris 10 Benchmark v5.1.0 #. audit_root_home () { print_function "audit_root_home" string="Root Home" check_message "${string}" if [ "${os_name}" = "SunOS" ]; then if [ "${os_name}" = "SunOS" ]; then if [ "${os_version}" = "10" ]; then command="grep root /etc/passwd | cut -f6 -d:" command_message "${command}" home_check=$( eval "${command}" ) log_file="${work_dir}/roothome.log" if [ "${home_check}" != "/root" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Root home directory incorrectly set" fix_message "mkdir -m 700 /root" fix_message "mv -i /.?* /root/" fix_message "passmgmt -m -h /root root" fi if [ "${audit_mode}" = 0 ]; then echo "${home_check}" >> "${log_file}" set_message "Root home directory correctly" mkdir -m 700 /root mv -i /.?* /root/ passmgmt -m -h /root root fi else if [ "${audit_mode}" = 1 ]; then inc_secure "Root home directory correctly set" fi fi if [ "${audit_mode}" = 2 ]; then restore_file="${restore_dir}/rootgroup.log" if [ -f "${restore_file}" ]; then home_check=$( cat "${restore_file}" ) restore_message "Root home directory \"${home_check}\"" eval "mv -i ${home_check}/.?* /" passmgmt -m -h "${group_check}" root fi fi fi fi else if [ "${os_name}" = "Linux" ]; then check_file_perms "/root" "0700" "root" "root" else na_message "${string}" fi fi } ================================================ FILE: modules/users/audit_root_path.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_root_path # # Check root path # # Refer to Section(s) 9.2.6 Page(s) 165-166 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.6 Page(s) 191-2 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.6 Page(s) 167 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.2.6 Page(s) 279-80 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 13.6 Page(s) 157-8 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 2.12.20 Page(s) 223 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9.6 Page(s) 76-7 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.6 Page(s) 120-1 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.6 Page(s) 257-8 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.6 Page(s) 271-2 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 5.4.2.5,6.2.6 Page(s) 702-4,271-2 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_root_path () { print_function "audit_root_path" string="Root PATH Environment Integrity" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "AIX" ]; then if [ "${audit_mode}" != 2 ]; then if [ "${audit_mode}" = 1 ]; then command="echo \"$PATH\" | grep \"::\"" command_message "${command}" path_check=$( eval "${command}" ) if [ "${path_check}" != "" ]; then inc_insecure "Empty directory in PATH" else inc_secure "No empty directory in PATH" fi command="echo \"$PATH\" | grep \":$\"" command_message "${command}" path_check=$( eval "${command}" ) if [ "${path_check}" != "" ]; then inc_insecure "Trailing : in PATH" else inc_secure "No trailing : in PATH" fi command="echo \"$PATH\" | sed -e 's/::/:/' -e 's/:$//' -e 's/:/ /g'" command_message "${command}" dir_list=$( eval "${command}" ) for dir_name in ${dir_list}$; do if [ "${dir_name}" = "." ]; then inc_insecure "PATH contains ." fi if [ -d "${dir_name}" ]; then command="find \"${dir_name}\" -maxdepth 1 -type f -writable \( -perm -g+w \)" command_message "${command}" group_test=$( eval "${command}" ) if [ -n "${group_test}" ]; then inc_insecure "Group write permissions set on directory \"${dir_name}\"" else inc_secure "Group write permission not set on directory \"${dir_name}\"" fi command="find \"${dir_name}\" -maxdepth 1 -type f -writable \( -perm -o+w \)" command_message "${command}" other_test=$( eval "${command}" ) if [ -n "${other_test}" ]; then inc_insecure "Other write permissions set on directory \"${dir_name}\"" else inc_secure "Other write permission not set on directory \"${dir_name}\"" fi fi done fi fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_shell_timeout.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_shell_timeout # # Check Shell Timeout settings # # Refer to Section(s) 5.4.3.2 Page(s) 714-8 CIS Ubuntu 24.04 Benchmark v1.0.0 # # Refer to: http://pubs.vmware.com/vsphere-55/topic/com.vmware.wssdk.apiref.doc/vim.option.OptionManager.html #. audit_shell_timeout () { print_function "audit_shell_timeout" string="Shell Timeout" check_message "${string}" if [ "${os_name}" = "VMkernel" ]; then for test in ESXiShellInteractiveTimeOut ESXiShellTimeOut; do timeout="3600" check_message "Timeout value for \"${test}\"" backup_file="${work_dir}/${test}" command="esxcli --formatter=csv --format-param=fields=\"Path,Int Value\" system settings advanced list | grep \"/UserVars/${test}\" | cut -f2 -d," command_message "${command}" current_value=$( eval "${command}" ) if [ "${audit_mode}" != "2" ]; then if [ "${current_value}" != "${timeout}" ]; then if [ "${audit_mode}" = "0" ]; then echo "${current_value}" > "${backup_file}" set_message "Timeout value for ${test} to ${timeout}" esxcli system settings advanced set -o "/UserVars/${test}" -i "${timeout}" fi if [ "${audit_mode}" = "1" ]; then inc_insecure "Timeout value for ${test} not set to ${timeout}" fix_message "esxcli system settings advanced set -o /UserVars/${test} -i ${timeout}" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Timeout value for ${test} is set to ${timeout}" fi fi else restore_file="${restore_dir}/${test}" if [ -f "${restore_file}" ]; then previous_value=$( cat "${restore_file}" ) if [ "${previous_value}" != "${current_value}" ]; then verbose_message "Restoring: Shell timeout to ${previous_value}" esxcli system settings advanced set -o "/UserVars/${test}" -i "${previous_value}" fi fi fi done else if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ]; then for check_file in /etc/.login /etc/profile /etc/skel/.bash_profile /etc/csh.login /etc/csh.cshrc \ /etc/zprofile /etc/skel/.zshrc /etc/skel/.bashrc /etc/bashrc /etc/skel/.bashrc /etc/login.defs; do check_file_value "is" "${check_file}" "TMOUT" "eq" "900" "hash" done else na_message "${string}" fi fi } ================================================ FILE: modules/users/audit_shells.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_shells # # Check that shells in /etc/shells exist # # Refer to Section(s) 5.4.2.8-5.4.3.1,7.1.9 Page(s) 711-5,950-1 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_shells () { print_function "audit_shells" string="Shells" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then check_file="/etc/shells" if [ -f "${check_file}" ]; then if [ "${audit_mode}" = 2 ]; then restore_file "${check_file}" "${restore_dir}" else check_shell="nologin" command="grep \"${check_shell}\" < \"${check_file}\" | grep -cv \"^#\"" command_message "${command}" nologin_check=$( eval "${command}" ) if [ "${nologin_check}" = "0" ]; then inc_secure "Shell \"${check_shell}\" is not in \"${check_file}\"" else inc_insecure "Shell \"${check_shell}\" is in \"${check_file}\"" fi check_file_comment "${check_file}" "nologin" "hash" command="grep -v '^#' \"${check_file}\"" command_message "${command}" check_shells=$( eval "${command}" ) for check_shell in ${check_shells}; do if [ ! -f "${check_shell}" ]; then if [ "${audit_mode}" = 1 ]; then inc_insecure "Shell \"${check_shell}\" in \"${check_file}\" does not exit" fi if [ "${audit_mode}" = 0 ]; then temp_file="${temp_dir}/shells" backup_file "${check_file}" grep -v "^${check_shell}" ${check_file} > "${temp_file}" cat "${temp_file}" > "${check_file}" fi fi done fi fi else na_message "${string}" fi } ================================================ FILE: modules/users/audit_super_users.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_super_users # # Check Super Users # # Refer to Section(s) 9.2.5 Page(s) 190-1 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 9.2.5 Page(s) 165 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 9.2.5 Page(s) 168 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 6.2.5 Page(s) 278 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 13.5 Page(s) 156-7 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 8.6 Page(s) 28 CIS FreeBSD Benchmark v1.0.5 # Refer to Section(s) 1.2.8 Page(s) 32 CIS AIX Benchmark v1.1.0 # Refer to Section(s) 9-5 Page(s) 75-6 CIS Solaris 11.1 Benchmark v1.0.0 # Refer to Section(s) 9.5 Page(s) 119-20 CIS Solaris 10 Benchmark v1.1.0 # Refer to Section(s) 6.2.5 Page(s) 256 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 6.2.5 Page(s) 270 CIS Ubuntu 16.04 Benchmark v1.0.0 #. audit_super_users () { print_function "audit_super_users" string="Accounts with UID 0" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "FreeBSD" ] || [ "${os_name}" = "AIX" ]; then if [ "${os_name}" = "AIX" ]; then check_chuser "su" "true" "sugroups" "system" "root" else if [ "${audit_mode}" != 2 ]; then lock_command="userdel ${user_name}" command="awk -F: '\$3 == \"0\" { print \$1 }' /etc/passwd | grep -v root" command_message "${command}" user_list=$( eval "${command}" ) for user_name in ${user_list}; do if [ "${audit_mode}" = 1 ]; then inc_insecure "UID 0 for User \"${user_name}\"" fix_message "${lock_command}" fi if [ "${audit_mode}" = 0 ]; then backup_file "/etc/shadow" backup_file "/etc/passwd" lock_message="Removing Account ${user_name} as it is UID 0" lock_command="userdel ${user_name}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi done if [ "${user_name}" = "" ]; then if [ "${audit_mode}" = 1 ]; then inc_secure "No accounts other than root have UID 0" fi fi else restore_file "/etc/shadow" "${restore_dir}" restore_file "/etc/passwd" "${restore_dir}" fi fi else na_message "${string}" fi } ================================================ FILE: modules/wheel/audit_pam_wheel.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_pam_wheel # # PAM Wheel group membership. Make sure wheel group membership is required to su. # # Refer to Section(s) 6.5 Page(s) 142-3 CIS CentOS Linux 6 Benchmark v1.0.0 # Refer to Section(s) 6.5 Page(s) 165-6 CIS RHEL 5 Benchmark v2.1.0 # Refer to Section(s) 6.5 Page(s) 145-6 CIS RHEL 6 Benchmark v1.2.0 # Refer to Section(s) 5.6 Page(s) 257-8 CIS RHEL 7 Benchmark v2.1.0 # Refer to Section(s) 9.5 Page(s) 135-6 CIS SLES 11 Benchmark v1.0.0 # Refer to Section(s) 5.5 Page(s) 235-6 CIS Amazon Linux Benchmark v2.0.0 # Refer to Section(s) 5.6 Page(s) 249 CIS Ubuntu 16.04 Benchmark v1.0.0 # Refer to Section(s) 5.2.7 Page(s) 594-5 CIS Ubuntu 24.04 Benchmark v1.0.0 #. audit_pam_wheel () { print_function "audit_pam_wheel" pam_module="pam_wheel" check_string="PAM ${pam_module} Configuration" check_message "${check_string}" if [ "${os_name}" = "Linux" ]; then check_file="/etc/pam.d/su" if [ -f "${check_file}" ]; then search_string="use_uid" if [ "${audit_mode}" != 2 ]; then command="grep \"^auth\" \"${check_file}\" | grep \"${search_string}$\" | awk '{print \$8}'" command_message "${command}" check_value=$( eval "${command}" ) if [ "${ansible_mode}" = 1 ]; then ansible_counter=$((ansible_counter+1)) ansible_value="audit_pam_wheel_${ansible_counter}" echo "" echo "- name: Checking ${check_string}" echo " command: sh -c \"cat ${check_file} | grep -v '^#' |grep '${search_string}$' |head -1 |wc -l\"" echo " register: ${ansible_value}" echo " failed_when: ${ansible_value} == 1" echo " changed_when: false" echo " ignore_errors: true" echo " when: ansible_facts['ansible_system'] == '${os_name}'" echo "" echo "- name: Fixing ${check_string}" echo " command: sh -c \"sed -i 's/^.*${search_string}$/#&/' ${check_file}\"" echo " when: ${ansible_value}.rc == 1 and ansible_facts['ansible_system'] == '${os_name}'" echo "" fi if [ "${check_value}" != "${search_string}" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Wheel group membership not required for su in \"${check_file}\"" verbose_message "cp ${check_file} ${temp_file}" "fix" verbose_message "cat ${temp_file} |awk '( \$1==\"#auth\" && \$2==\"required\" && \$3~\"${pam_module}.so\" ) { print \"auth\t\trequired\t\",\$3,\"\tuse_uid\"; next }; { print }' > ${check_file}" "fix" verbose_message "rm ${temp_file}" "fix" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" verbose_message "Setting: Su to require wheel group membership in PAM in \"${check_file}\"" cp "${check_file}" "${temp_file}" awk '( $1=="#auth" && $2=="required" && $3~"${pam_module}.so" ) { print "auth\t\trequired\t",$3,"\tuse_uid"; next }; { print }' < "${temp_file}" > ${check_file} if [ -f "$tuse_file" ]; then rm "${temp_file}" fi fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Wheel group membership required for su in \"${check_file}\"" fi fi else restore_file "${check_file}" "${restore_dir}" fi fi else na_message "${check_string}" fi } ================================================ FILE: modules/wheel/audit_wheel_group.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_wheel_group # # Make sure there is a wheel group so privileged account access is limited. #. audit_wheel_group () { print_function "audit_wheel_group" string="Wheel Group" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ]; then check_file="/etc/group" if [ "${audit_mode}" != 2 ]; then command="grep \"^${wheel_group}:\" \"${check_file}\" |wc -c" command_message "${command}" check_value=$( eval "${command}" ) if [ "${check_value}" = "0" ]; then if [ "${audit_mode}" = "1" ]; then inc_insecure "Wheel group \"${wheel_group}\" does not exist in \"${check_file}\"" fi if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking ${string}" echo " group:" echo " name: ${wheel_group}" echo " when: ansible_facts['ansible_system'] == '${os_name}' or ansible_facts['ansible_system'] == '${os_name}'" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message="Adding wheel group \"${wheel_group}\" to \"${check_file}\"" lock_command="groupadd ${wheel_group} ; usermod -G ${wheel_group} root" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi else if [ "${audit_mode}" = "1" ]; then inc_secure "Wheel group \"${wheel_group}\" ${exists} in \"${check_file}\"" fi fi else restore_file "${check_file}" "${restore_dir}" fi else na_message "${string}" fi } ================================================ FILE: modules/wheel/audit_wheel_su.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_wheel_su # # Make sure su has a wheel group ownership #. audit_wheel_su () { print_function "audit_wheel_su" string="Wheel group ownership" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then command="command -v su 2> /dev/null" command_message "${command}" check_file=$( eval "${command}" ) check_file_perms "${check_file}" "4750" "root" "${wheel_group}" else na_message "${string}" fi } ================================================ FILE: modules/wheel/audit_wheel_users.sh ================================================ #!/bin/sh # shellcheck disable=SC1090 # shellcheck disable=SC2034 # shellcheck disable=SC2154 # audit_wheel_users # # Check users in wheel group have recently logged in, if not lock them # audit_wheel_users () { print_function "audit_wheel_users" string="Wheel Users" check_message "${string}" if [ "${os_name}" = "SunOS" ] || [ "${os_name}" = "Linux" ] || [ "${os_name}" = "Darwin" ]; then check_file="/etc/group" if [ "${audit_mode}" != 2 ]; then command="grep \"^${wheel_group}:\" \"${check_file}\" | cut -f4 -d: | sed 's/,/ /g'" command_message "${command}" user_list=$( eval "${command}" ) if [ "${user_list}" = "" ]; then inc_insecure "No users in wheel group" fi for user_name in ${user_list}; do command="last -1 \"${user_name}\" | grep '[a-z]' | awk '{print \$1}'" command_message "${command}" last_login=$( eval "${command}" ) if [ "${last_login}" = "wtmp" ]; then command="read -r \"/etc/shadow\"" command_message "${command}" if eval "${command}"; then command="grep \"^${user_name}:\" /etc/shadow | grep -v 'LK' | cut -f1 -d:" command_message "${command}" lock_test=$( eval "${command}" ) if [ "${lock_test}" = "${user_name}" ]; then if [ "${ansible_mode}" = 1 ]; then echo "" echo "- name: Checking password lock for ${user_name}" echo " user:" echo " name: ${user_name}" echo " password_lock: yes" echo "" fi if [ "${audit_mode}" = 1 ]; then inc_insecure "User ${user_name} has not logged in recently and their account is not locked" fi if [ "${audit_mode}" = 0 ]; then backup_file "${check_file}" lock_message "User \"${user_name}\" to locked" lock_command="passwd -l ${user_name}" run_lockdown "${lock_command}" "${lock_message}" "sudo" fi fi fi fi done else restore_file "${check_file}" "${restore_dir}" fi else na_message "${string}" fi }