NetAppSecCheck.ps1
<#
.NOTES Information on running PowerShell scripts can be found here: -http://ss64.com/ps/syntax-run.html -https://technet.microsoft.com/en-us/library/bb613481.aspx This script requires PowerShell 7 or later to run, information on installing or upgrading PowerShell can be found here: -https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.3 File Name: NetAppSecCheck.ps1 .SYNOPSIS Version: 1.0 - Initial release .DESCRIPTION The intention of this script is to provide a quick check of several security configurations. Typically the following tools provide security related information for ONTAP clusters: -System Manager Dashboard -Unified Manager cluster security objectives -Active IQ Digital Advisor If a more thorough review is necessary of your environment, engage NetApp Services and request a Data Protection and Security Assessment The documents referenced in the KB article linked below should be consulted for the most up to date information -https://kb.netapp.com/onprem/ontap/os/How_to_perform_a_security_health_check_with_a_script_in_ONTAP .EXAMPLE .\NetAppSecCheck.ps1 All required values will be prompted for. #> <#PSScriptInfo .VERSION 1.0 .GUID 5a91e6dd-0287-4a5b-860b-eed6abf74b55 .AUTHOR Dan Tully .COMPANYNAME .COPYRIGHT .TAGS .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .PRIVATEDATA #> #Requires -Version 7.0 #region Begin logging $Now = get-date -f MM-dd-yyyy-HHmmss Start-Transcript -UseMinimalHeader -Path ".\$Now.txt" #endregion #region Gather cluster address and credentials $NTAPCluster = Read-Host "Please enter the IP address or DNS name of the cluster to evaluate" $Credential = Get-Credential #endregion #region Test Connection/Authentication Try { $AuthCheck = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/cluster" -Credential $Credential -SkipCertificateCheck } Catch { if($_.ErrorDetails.Message) { Write-Host $_.ErrorDetails.Message } else { Write-Host $_ } Exit } #endregion #region General info Write-Host Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host Write-Host "The intention of this script is to provide a quick check of several security configurations." Write-Host Write-Host " Typically the following tools provide security related information for ONTAP clusters:" Write-Host " System Manager Dashboard" Write-Host " Unified Manager cluster security objectives" Write-Host " Active IQ Digital Advisor" Write-Host Write-Host "If a more thorough review is necessary of your environment, engage NetApp Services and request a Data Protection and Security Assessment" Write-Host Write-Host "The documents referenced in the KB article linked below should be consulted for the most up to date information" Write-Host Write-Host " https://kb.netapp.com/onprem/ontap/os/How_to_perform_a_security_health_check_with_a_script_in_ONTAP" Write-Host Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-Host #endregion #region Display ONTAP Version $Cluster = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/cluster" -Credential $Credential -SkipCertificateCheck $ONTAPGen= $Cluster.Version.generation $ONTAPMaj= $Cluster.Version.major $ONTAPMin= $Cluster.Version.minor $Version = [string]$ONTAPGen+"."+[string]$ONTAPMaj+"."+[string]$ONTAPMin $ChkVersion = $ONTAPMaj + $ONTAPMin / 10 Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: Running a recommended release of ONTAP" Write-host "Reference: SU2" Write-host Write-host " ONTAP Version:" $Version Write-host Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display Telnet and RSH status Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: Telnet and Remote Shell (RSH) should be disabled" Write-host "Reference: System Manager insights and TR-4569 section "Application methods"" $MgmtProtocols = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/protocol?fields=application,enabled" -Credential $Credential -SkipCertificateCheck $MgmtProtocolsOut = ForEach ($_ in $MgmtProtocols.records) { new-object psobject -Property @{ Application = ($_.application).ToString() Enabled = ($_.enabled).ToString() } } $MgmtProtocolsOut | Format-Table Application,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display Multi-admin-verify status Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: Multi-admin verification should be enabled" write-host "Reference: TR-4569 section "Multi-admin verification"" If ($ChkVersion -ge 11.1) { $MAV = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/multi-admin-verify" -Credential $Credential -SkipCertificateCheck $MAVOut = new-object psobject -Property @{ Enabled = ($MAV.enabled).ToString() "Required Approvers" = ($MAV.required_approvers).ToString() } $MAVOut | Format-Table Enabled,"Required Approvers" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " Multi-admin-verify is not supported on this release. Consider upgrading to 9.11.1 or later." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display Cluster log forwarding destinations Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: Offloading of syslog information should be configured" Write-host "Reference: TR-4569 section "Sending out syslog"" $LogForwarding = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/cluster/log" -Credential $Credential -SkipCertificateCheck Write-host If ($LogForwarding.num_records -ne 0) { $LogData = ForEach ($_ in $LogForwarding.records) { new-object psobject -Property @{ Destination = ($_.Destination).ToString() Port = ($_.Port).ToString() } } Write-host " Cluster Log Destinations" $LogData | Format-Table Destination,Port | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display Self-signed certificates Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: On production systems no self-signed ceritficates should exist" write-host " (the recommendation is met if no results are returned)" Write-host "Reference: TR-4569 section "Creating a CA-signed digital certificate"" Write-host $Certs = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/certificate?self_signed=true&type=server&fields=self_signed,common_name,vserver,type" -Credential $Credential -SkipCertificateCheck If ($Certs.num_records -ne 0) { $CertOut = ForEach ($_ in $Certs.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() CommonName = ($_.common_name).ToString() Serial = ($_.serial).ToString() CA = ($_.ca).ToString() Type = ($_.type).ToString() "Self-Signed" = ($_.self_signed).ToString() } } $CertOut | Format-Table Vserver,CommonName,Serial,CA,Type,"Self-Signed" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display OCSP status Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: OCSP should be enabled" Write-host "Reference: TR-4569 section "Online certificate status protocol"" $OCSP = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/config/ocsp?fields=application,is_ocsp_enabled" -Credential $Credential -SkipCertificateCheck $OCSPOut = ForEach ($_ in $OCSP.records) { new-object psobject -Property @{ Application = ($_.application).ToString() "OCSP Enabled" = ($_.is_ocsp_enabled).ToString() } } $OCSPOut | Format-Table Application,"OCSP Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display FIPS configuration Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: FIPS Mode should be enabled" Write-host "Reference: System Manager insights and TR-4569 section "Managing TLS and SSL"" $FIPS = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/config?fields=is_fips_enabled" -Credential $Credential -SkipCertificateCheck $FIPSOut = ForEach ($_ in $FIPS.records) { new-object psobject -Property @{ Interface = ($_.interface).ToString() "FIPS Enabled" = ($_.is_fips_enabled).ToString() } } $FIPSOut | Format-Table Interface,"FIPS Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display CLI Timeout Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: CLI timeout value should match your organization's requirements" Write-host "Reference: TR-4569 section "CLI session timeout"" $SystemTimeout = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/system/timeout" -Credential $Credential -SkipCertificateCheck write-host write-host " CLI session timeout:" $SystemTimeout.timeout "minutes" write-host Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display login banner and motd configuration Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: The login banner and message of the day (motd) should match your organization's requirements" Write-host "Reference: System Manager insights and TR-4569 section "Login banners" and "Message of the day"" Write-host $Banner = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login/banner" -Credential $Credential -SkipCertificateCheck $Motd = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login/motd" -Credential $Credential -SkipCertificateCheck If ($Banner.num_records -ne 0){ Write-host " Login banner configured - true" Write-host } else{ Write-host " Login banner configured - false" Write-host } If ($Motd.num_records -ne 0){ Write-host " MOTD configured - true" Write-host } else{ Write-host " MOTD configured - false" Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display cbc ciphers Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: No ciphers should exist that have names containing"cbc"" write-host " (the recommendation is met if no results are returned)" Write-host "Reference: System Manager insights" $SecuritySsh = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/ssh?ciphers=*cbc*" -Credential $Credential -SkipCertificateCheck $SecSSHData = @() If ($SecuritySsh.num_records -ne 0) { write-host write-host " Problematic Ciphers" ForEach ($_ in $SecuritySsh.records) { $Vserver = $_.vserver $Ciphers = $_.ciphers -split "," ForEach ($_ in $Ciphers) { If ($_.contains("cbc")) { $SecSSHData += New-Object -TypeName psobject -Property @{VServer=$VServer; Cipher=$_} } } } $SecSSHData | Format-Table VServer,Cipher | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { write-host write-host " No Problematic Ciphers Found." write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display NTP Servers Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: The number of servers configured for NTP should not be less than 3" Write-host "Reference: System Manager insights and TR-4569 section "Network Time Protocol"" $NTPServers = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/cluster/time-service/ntp/server" -Credential $Credential -SkipCertificateCheck If ($NTPServers.num_records -ne 0) { $NTPOut = ForEach ($_ in $NTPServers.records) { new-object psobject -Property @{ "NTP Servers" = ($_.Server ).ToString() } } $NTPOut | Format-Table "NTP Servers" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No NTP Servers Found." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display Autosupport Configuration Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: AutoSupport should use a secure protocol (HTTPS) and should be enabled" Write-host "Reference: System Manager insights and TR-4569 section "NetApp AutoSupport"" $ASUPConf = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/support/autosupport" -Credential $Credential -SkipCertificateCheck $AsupOut = ForEach ($_ in $ASUPConf) { new-object psobject -Property @{ Transport = ($_.transport ).ToString() Enabled = ($_.enabled ).ToString() } } $ASUPOut | Format-Table Transport,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display cluster agent connections for 9.10 and later If ($ChkVersion -ge 10) { Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: Cloud Insights provides an external mode FPolicy server" Write-host "Reference: TR-4572 section "Cloud Insights"" $ClusterAgent = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/cluster/agent/connection" -Credential $Credential -SkipCertificateCheck #Need to test on a configured system If ($ClusterAgent.num_records -ne 0) { $ClusterAgent.records | Format-Table | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host } #endregion #region Display FPolicy configuration Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: FPolicy should be configured" Write-host "Reference: System Manager insights" $Fpolicy = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/vserver/fpolicy?fields=status,engine" -Credential $Credential -SkipCertificateCheck If ($Fpolicy.num_records -ne 0) { $FpolicyOut = ForEach ($_ in $Fpolicy.records) { new-object psobject -Property @{ VServer = ($_.vserver ).ToString() "Policy Name" = ($_.policy_name ).ToString() Status = ($_.status ).ToString() Engine = ($_.engine ).ToString() } } $FpolicyOut | Format-Table VServer,"Policy Name",Status,Engine | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host #endregion #region Display Admin and Diag user status Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: Built in accounts should be locked" Write-host "Reference: System Manager insights and TR-4569 section "Default administrative accounts"" $AdminUser = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/accounts?name=admin&fields=locked" -Credential $Credential -SkipCertificateCheck $DiagUser = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/accounts?name=diag&fields=locked" -Credential $Credential -SkipCertificateCheck $Locked = $AdminUser.records + $DiagUser.records $LockedOut = ForEach ($_ in $Locked) { new-object psobject -Property @{ Username = ($_.name ).ToString() Locked = ($_.locked ).ToString() } } $LockedOut | Format-table Username,Locked | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host #endregion #region Display users with telnet and rsh application access Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: No logins should exist with the telnet or rsh application" write-host " (the recommendation is met if no results are returned)" Write-host "Reference: TR-4569 section "Application methods"" $RSH = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?application=rsh&fields=role,second_authentication_method,is_account_locked" -Credential $Credential -SkipCertificateCheck $Telnet = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?application=telnet&fields=role,second_authentication_method,is_account_locked" -Credential $Credential -SkipCertificateCheck If ($RSH.num_records -ne 0) { $RSHOut = ForEach ($_ in $RSH.records) { new-object psobject -Property @{ VServer = ($_.vserver ).ToString() Username = ($_.user_or_group_name ).ToString() Application = ($_.application ).ToString() AuthMethod = ($_.authentication_method ).ToString() "Role Name" = ($_.role ).ToString() Locked = ($_.is_account_locked ).ToString() "2ndAuthMethod" = ($_.second_authentication_method ).ToString() } } $RSHOut | Format-table username,vserver,application,"role name",authmethod,"2ndAuthMethod",Locked | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No users found with RSH application access." Write-host } If ($Telnet.num_records -ne 0) { $TelnetOut = ForEach ($_ in $Telnet.records) { new-object psobject -Property @{ VServer = ($_.vserver ).ToString() Username = ($_.user_or_group_name ).ToString() Application = ($_.application ).ToString() AuthMethod = ($_.authentication_method ).ToString() "Role Name" = ($_.role ).ToString() Locked = ($_.is_account_locked ).ToString() "2ndAuthMethod" = ($_.second_authentication_method ).ToString() } } $TelnetOut | Format-table username,vserver,application,"role name",authmethod,"2ndAuthMethod",Locked | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No users found with Telnet application access." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host #endregion #region Display password complexity settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: Configured password parameters should match your organization's policy" Write-host "Reference: TR-4569 section "Password parameters"" $Passwd = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login/role/config?fields=passwd-minlength,passwd-min-special-chars,passwd-min-digits,passwd-min-lowercase-chars,passwd-min-uppercase-chars,passwd-alphanum" -Credential $Credential -SkipCertificateCheck If ($Passwd.num_records -ne 0) { $PasswdOut = ForEach ($_ in $Passwd.records) { new-object psobject -Property @{ VServer = ($_.vserver ).ToString() Role = ($_.role ).ToString() Alphanumeric = ($_.passwd_alphanum ).ToString() "Min Len" = ($_.passwd_minlength ).ToString() "Min Spec Chars" = ($_.passwd_min_special_chars ).ToString() "Min Lowercase" = ($_.passwd_min_lowercase_chars ).ToString() "Min Uppercase" = ($_.passwd_min_uppercase_chars ).ToString() "Min Digits" = ($_.passwd_min_digits ).ToString() } } $PasswdOut | Format-table vserver,role,Alphanumeric,"Min Len","Min Spec Chars","Min Lowercase","Min Uppercase","Min Digits" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host #endregion #region Display various user configuration settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: For each login the authentication-method should be public key for machine access and can be password for user access" Write-host " The second-authentication-method should not be none to enable MFA" Write-host " The role should be the appropriate granting them the appropriate privilege to perform their job function or required tasks" Write-host " The hash-function should be sha512" Write-host "Reference: TR-4569 section "SHA-512 support" and "Managing SSHv2" and "Roles, applications, and authentication" and " Write-host " TR-4647 section "ONTAP SSH two-factor chained authentication"" $Users = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?fields=second-authentication-method,hash-function,is-account-locked,role" -Credential $Credential -SkipCertificateCheck If ($Users.num_records -ne 0) { $UsersOut = ForEach ($_ in $Users.records) { new-object psobject -Property @{ VServer = ($_.vserver ).ToString() Username = ($_.user_or_group_name ).ToString() Application = ($_.application ).ToString() AuthMethod = ($_.authentication_method ).ToString() "Role Name" = ($_.role ).ToString() Locked = ($_.is_account_locked ).ToString() "2ndAuthMethod" = ($_.second_authentication_method ).ToString() "Hash Function" = ($_.hash_function ).ToString() } } $UsersOut | Format-table username,vserver,application,"role name",authmethod,"2ndAuthMethod",Locked,"Hash Function" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display SVM API authentication details Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: For any SVM with client-enabled access, all related logins that are performing SDK or REST API calls should " write-host " use cert for Authentication Method field" Write-host "Reference: TR-4569 section "Certificate-based API access"" $SSL = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/ssl?fields=client-enabled" -Credential $Credential -SkipCertificateCheck $HTTP = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?application=http" -Credential $Credential -SkipCertificateCheck $ONTAPI = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?application=ontapi" -Credential $Credential -SkipCertificateCheck $SSLOut = ForEach ($_ in $SSL.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() "Client Enabled" = ($_.client_enabled).ToString() } } Write-host Write-host " SSL Configuration" $SSLOut | Format-Table VServer,"Client Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } $HTTPOut = ForEach ($_ in $HTTP.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() Username = ($_.user_or_group_name).ToString() Application = ($_.application).ToString() AuthMethod = ($_.authentication_method).ToString() } } If ($HTTP.records.num_records -ne 0) { write-host " HTTP Users" $HTTPOut | Format-Table VServer,Username,Application,AuthMethod | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No HTTP Users Found." Write-host } $ONTAPIOut = ForEach ($_ in $ONTAPI.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() Username = ($_.user_or_group_name).ToString() Application = ($_.application).ToString() AuthMethod = ($_.authentication_method).ToString() } } If ($ONTAPI.records.num_records -ne 0) { write-host " ONTAPI Users" $ONTAPIOut | Format-Table VServer,Username,Application,AuthMethod | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No ONTAPI Users Found." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display REST API /api/storage/volumes access for 9.10 and later If ($ChkVersion -ge 10) { Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: You can prevent ONTAP administrators from using REST APIs for file access by setting access level " write-host " for /api/storage/volumes to none" Write-host "Reference: TR-4569 section "Effect of REST APIs on NAS auditing"" $RestRoles = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login/rest-role?api=/api/storage/volumes&fields=access" -Credential $Credential -SkipCertificateCheck $RestOut = ForEach ($_ in $RestRoles.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() Role = ($_.role).ToString() API = ($_.api).ToString() Access = ($_.Access).ToString() } } $RestOut | Format-Table VServer,Role,API,Access | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host } #endregion #region Display SAML configuration Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host "Recommendation: SAML should be configured" Write-host "Reference: TR-4647 section "The requirement for strong administrative credentials"" $Samlsp = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/saml-sp/status?fields=status,is_enabled" -Credential $Credential -SkipCertificateCheck If ($Samlsp.records.num_records -ne 0) { $SamlOut = ForEach ($_ in $Samlsp.records) { new-object psobject -Property @{ Node = ($_.node).ToString() Status = ($_.status).ToString() Enabled = ($_.is_enabled).ToString() } } $SamlOut | Format-Table Node,Status,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display CIFS signing configuration Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: For each SVM configured with CIFS the is-signing-required should be true" write-host "Reference: TR-4569 section "CIFS SMB signing and sealing"" $CIFSSigning = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/vserver/cifs/security?is_signing_required=!null" -Credential $Credential -SkipCertificateCheck If ($CIFSSigning.num_records -ne 0) { $CIFSOut = ForEach ($_ in $CIFSSigning.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() "Signing Required" = ($_.is_signing_required).ToString() } } $CIFSOut | Format-Table VServer,"Signing Required" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display LDAP session security settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: For each SVM configured with CIFS session-security-for-ad-ldap should be set to a minimum of sign " write-host " to match your organization's requirements" write-host "Reference: TR-4835 section "Microsoft LDAP channel binding requirement"" $LDAPBinding = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/vserver/cifs/security?session-security-for-ad-ldap=!null" -Credential $Credential -SkipCertificateCheck If ($LDAPBinding.num_records -ne 0) { $LDAPOut = ForEach ($_ in $LDAPBinding.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() "Session Security for AD LDAP" = ($_.session_security_for_ad_ldap).ToString() } } $LDAPOut | Format-Table VServer,"Session Security for AD LDAP" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display Audit settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: NAS auditing should be enabled" write-host "Reference: TR-4569 section "NAS file system auditing"" $Audit = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/vserver/audit?fields=vserver,state" -Credential $Credential -SkipCertificateCheck If ($Audit.num_records -ne 0) { $AuditOut = ForEach ($_ in $Audit.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() Enabled = ($_.state).ToString() } } $AuditOut | Format-Table VServer,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Auditing Configuration Found." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display NIS config Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: NIS should not be configured (the recommendation is met if no results are returned)" write-host "Reference: TR-4569 section "Authentication methods"" $NISData = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/svm/svms?nis.domain=!null" -Credential $Credential -SkipCertificateCheck If ($NISData.num_records -ne 0) { $NISSVMs = ForEach ($_ in $NISData.records) { new-object psobject -Property @{ VServer = ($_.name).ToString() NISDomain = ($_.nis.domain).ToString() } } $NISSVMs | Format-Table vserver,nisdomain | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display volumes without snapshot policies Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: All volumes should have Snapshot policies (the recommendation is met if no results are returned)" write-host "Reference: System Manager insights" $NullSS = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?snapshot_policy=null&is_cluster_volume=true" -Credential $Credential -SkipCertificateCheck If ($NullSS.num_records -ne 0) { $NullSSData = ForEach ($_ in $NullSS.records) { new-object psobject -Property @{ Volume = ($_.volume).ToString() "Snapshot Policy" = "-" VServer = ($_.vserver).ToString() } } $NullSSData | Format-Table volume,"Snapshot Policy",VServer | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Volumes with a Snapshot Policy of NULL." Write-host } $NoneSS = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?snapshot_policy=none&is_cluster_volume=true" -Credential $Credential -SkipCertificateCheck If ($NoneSS.num_records -ne 0) { $NoneSSData = ForEach ($_ in $NoneSS.records) { new-object psobject -Property @{ Volume = ($_.volume).ToString() "Snapshot Policy" = ($_.snapshot_policy).ToString() VServer = ($_.vserver).ToString() } } $NoneSSData | Format-Table volume,"Snapshot Policy",VServer | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Volumes with a Snapshot Policy of None." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display snapshot autodelete settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: Snapshot auto-deletion should not be enabled for data volumes" write-host "Reference: System Manager insights" $AD = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume/snapshot/autodelete?enabled=true" -Credential $Credential -SkipCertificateCheck If ($AD.num_records -ne 0) { $ADData = ForEach ($_ in $AD.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() Enabled = ($_.enabled).ToString() Volume = ($_.volume).ToString() } } $ADData | Format-Table VServer,Volume,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display anti-ransomware settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: SVMs should be configured for anti-ransomware" write-host "Reference: System Manager insights" If ($ChkVersion -ge 10) { $AR = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/svm/svms?fields=anti_ransomware_default_volume_state" -Credential $Credential -SkipCertificateCheck If ($AR.num_records -ne 0) { $ARData = ForEach ($_ in $AR.records) { new-object psobject -Property @{ VServer = ($_.name).ToString() "Anti Ransomware Default Volume State" = ($_.anti_ransomware_default_volume_state).ToString() } } $ARData | Format-Table VServer,"Anti Ransomware Default Volume State" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } } Else { Write-host Write-host " Anti-Ransomware Protection is not supported on this release. Consider upgrading to 9.10 or later." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display anti-ransomware settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: Volume anti-ransomware-state should be enabled" write-host "Reference: System Manager insights" If ($ChkVersion -ge 10) { $VAR = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?is-cluster-volume=true&fields=anti-ransomware-state" -Credential $Credential -SkipCertificateCheck If ($VAR.num_records -ne 0) { $VARData = ForEach ($_ in $VAR.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() Volume = ($_.volume).ToString() "Anti Ransomware State" = ($_.anti_ransomware_state).ToString() } } $VARData | Format-Table VServer,Volume,"Anti Ransomware State" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } } Else { Write-host Write-host " Anti-Ransomware Protection is not supported on this release. Consider upgrading to 9.10 or later." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display snapshot locking settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: snapshot-locking-enabled should be true for all volumes with snapshots" write-host "Reference: TR-4569 section "Snapshot copy locking"" If ($ChkVersion -ge 12.1) { $SSLocking = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?fields=snapshot_locking_enabled" -Credential $Credential -SkipCertificateCheck If ($SSLocking.num_records -ne 0) { $SSLockingOut = ForEach ($_ in $SSLocking.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() Volume = ($_.volume).ToString() "Snapshot Locking Enabled" = ($_.snapshot_locking_enabled).ToString() } } $SSLockingOut | Format-Table VServer,Volume,"Snapshot Locking Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } } Else { Write-host Write-host " Snapshot Copy Locking is not supported on this release. Consider upgrading to 9.12.1 or later." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display KeyManager and encryption settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: A key-manager should be configured and encryption should be enabled at either the disk, aggregate, or volume layer " write-host "Reference: TR-4569 section "Storage encryption"" $KeyManager = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/key-managers" -Credential $Credential -SkipCertificateCheck If ($KeyManager.num_records -ne 0) { Write-host Write-host " Key-manager is configured." } Else { Write-host Write-host " No Key-manager Found." } $DriveProt = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/storage/aggregate?fields=drive-protection-enabled,node" -Credential $Credential -SkipCertificateCheck If ($DriveProt.num_records -ne 0) { $DriveProtData = ForEach ($_ in $DriveProt.records) { new-object psobject -Property @{ Aggregate = ($_.aggregate).ToString() Node = ($_.node).ToString() "Drive Protection Enabled" = ($_.drive_protection_enabled).ToString() } } $DriveProtData | Format-Table Aggregate,Node,"Drive Protection Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } $VolEnc = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?fields=encryption-type,is-encrypted" -Credential $Credential -SkipCertificateCheck If ($VolEnc.num_records -ne 0) { $VolEncData = ForEach ($_ in $VolEnc.records) { new-object psobject -Property @{ VServer = ($_.vserver).ToString() Volume = ($_.volume).ToString() "Encryption Type" = ($_.encryption_type).ToString() "Is Encrypted" = ($_.is_encrypted).ToString() } } $VolEncData | Format-Table VServer,Volume,"Encryption Type","Is Encrypted" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Results Returned." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display cluster peer encryption Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: Cluster peers should be configured with tls-psk for the encryption protocol" write-host "Reference: TR-4569 section "Data replication encryption"" $ClusterPeer = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/cluster/peer?fields=cluster,encryption_protocol_proposed,encryption_protocol" -Credential $Credential -SkipCertificateCheck If ($ClusterPeer.num_records -ne 0) { $ClusterPeerOut = ForEach ($_ in $ClusterPeer.records) { new-object psobject -Property @{ Cluster = ($_.cluster).ToString() "Encryption Protocol" = ($_.encryption_protocol).ToString() } } $ClusterPeerOut | Format-Table Cluster,"Encryption Protocol" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host Write-host " No Cluster Peer Relationships Found." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #region Display IPSec configuration settings Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" write-host "Recommendation: When required ipsec is configured and policies created" write-host "Reference: TR-4569 section "IPsec data-in-flight encryption"" If ($ChkVersion -ge 8) { $IPsec = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/ipsec?fields=*" -Credential $Credential -SkipCertificateCheck Write-host Write-host " IPsec Enabled -" $IPsec.enabled Write-host $IPsecPolicy = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/ipsec/policies" -Credential $Credential -SkipCertificateCheck If ($IPsecPolicy.num_records -ne 0) { $IPsecPolicy.records | Format-Table | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ } } Else { Write-host " No IPsec Policies Found." Write-host } } Else { Write-host Write-host " IPsec is not supported on this release. Consider upgrading to 9.8 or later." Write-host } Write-host "--------------------------------------------------------------------------------------------------------------------------------------------" Write-host #endregion #stop logging Stop-Transcript |