#requires -version 4 <# .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 File Name: RiskResolverCertificate.ps1 .COMPONENT -NetApp PowerShell Toolkit 3.2.1 or newer: http://mysupport.netapp.com/NOW/download/tools/powershell_toolkit/ .SYNOPSIS Version: 1.5 - Set toolkit import just to import and not check for version (due to new versioning of current releases) Added option to check certificates that expire X number of days in the future Added a check if there are multiple certificates in the same SVM not to continue if they are of the same common name Added more inline comments 1.4 - Changed self-signing check and for type of server only to be returned. 1.3 - Changed to handle single node clusters. 1.2 - Changed to 8.3+ only to better verify that the certificate is self signed and implemented a workaround with how the toolkit interacts with 9.x for setting a certificate 1.1 - Added prompt for confirming each action 1.0 - Original release Known Issues: -A destination SVM DR instance with identity preserve parameter enabled copies the certificate from the source SVM. An attempt to recreate the certificate of such a destination SVM will produce a warning that is not possible. -Some single node clusters that have pre-8.3 ONTAP node certificates might not properly cleanup those certificates. Those certificates are no longer used by ONTAP and this is a very rare scenario. .DESCRIPTION Clustered Data ONTAP (also known as ONTAP) uses self-signed certificates by default for management of the environment. These certificates have a typical expiration date of 1 year (365 days). This KB describes the process to recreate the certificates: https://kb.netapp.com/support/index?page=content&id=1014389&locale=en_US&access=s This script handles the steps outlined in the article by doing the following: -Connecting to a cluster -Collecting all existing certificates -Ensuring the certificate is self-signed -Deletes the self-signed certificate -Creates a new certificate with the same properties as the previous one with a 10 year expiration -Configures SSL on the SVM to use the new certificate Special thanks for inspiration from N.E. at: http://community.netapp.com/t5/OnCommand-Storage-Management-Software-Discussions/Can-t-add-a-cluster/m-p/62376 .PARAMETER Cluster The cluster management LIF IP address or resolvable DNS name for the cluster to connect to. .PARAMETER Username Username to use to connect to the cluster. .PARAMETER Password Password used to connect to the cluster. This is in clear text. If not provided you will be prompted for the password during the script and it will be obfuscated. .EXAMPLE .\RiskResolverCertificate.ps1 Running without any parameters will prompt for all necessary values .EXAMPLE .\RiskResolverCertificate.ps1 -Cluster NetApp1 -Username admin -Password MyPassword Connects to the cluster named NetApp1 with the provided credentials. .LINK http://community.netapp.com/t5/Microsoft-Cloud-and-Virtualization-Discussions/Risk-Resolver-Certificate-Renew-Recreate/m-p/120505 #> #region Parameters and Variables [CmdletBinding(PositionalBinding=$False)] Param( [Parameter(Mandatory=$False)] [string]$Cluster, [Parameter(Mandatory=$False)] [string]$Username, [Parameter(Mandatory=$False)] [string]$Password ) #Get today's date $CurrentDate = Get-Date #Using 10 years which is the max, change if different value is desired $NewCertificateExpireDays = 3650 $ProceedCertificateRenewal = $true #Import toolkit Import-Module DataONTAP #endregion #region Main Body #Connect to the cluster If ($Cluster.Length -eq 0) { $Cluster = Read-host "Enter the cluster management LIF DNS name or IP address" } $Cluster = $Cluster.Trim() If ($Username.Length -eq 0) { $Username = Read-Host "Enter username for connecting to the cluster" } If ($Password.Length -eq 0) { $SecurePassword = Read-Host "Enter the password for" $Username -AsSecureString } else { $SecurePassword = New-Object -TypeName System.Security.SecureString $Password.ToCharArray() | ForEach-Object {$SecurePassword.AppendChar($_)} } #Preparing credential object to pass $Credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $Username, $SecurePassword Write-Host "Attempting connection to $Cluster" $ClusterConnection = Connect-NcController -name $Cluster -Credential $Credentials #Only proceeding with valid connection to cluster If (!$ClusterConnection) { Write-Host "Unable to connect to NetApp cluster, please ensure all supplied information is correct and try again" -ForegroundColor Yellow Exit } #Get basic cluster information $ClusterInformation = Get-NcCluster $Nodes = Get-NcNode $NumberOfNodes = $Nodes.Length $NodeInformation = Get-NcNode Write-Host "Working with cluster:" $ClusterInformation.ClusterName Write-Host "Which contains the following Nodes:" $NodeInformation.Node $Found83Plus = $False $OntapVersonInfo = Get-NcSystemVersionInfo $FullOTAPVersionDetails = $OntapVersonInfo.Version $FullOTAPVersionDetails = $FullOTAPVersionDetails.ToString() $FullONTAPVersion = $OntapVersonInfo.VersionTuple Write-Host "ONTAP version:" $FullONTAPVersion $SegmentOntapVersion = $FullONTAPVersion -split '\.' $FamilyRelease = $SegmentOntapVersion[0] $MajorRelease = $SegmentOntapVersion[1] $MinorRelease = $SegmentOntapVersion[2] #Most of the script requires 9.x but some applies to 8.3 If (($FamilyRelease -eq 8 -and $MajorRelease -eq 3) -or $FamilyRelease -eq 9) { $Found83Plus = $true } #Only continue of version of ONTAP is at least 8.3 If ($Found83Plus) { #Ask how to proceed $RenewNonExpiredCertificatesChoice = $host.ui.PromptForChoice("Renew non-expired certificates?","Please select yes or no",[System.Management.Automation.Host.ChoiceDescription[]]("&Yes","&No"),1) Switch ($RenewNonExpiredCertificatesChoice) { 0 {$RenewNonExpiredCertificates = $true} 1 {$RenewNonExpiredCertificates = $false} } #Ask for checking number of days in future for expiration If (!$RenewNonExpiredCertificates) { $DaysOffset = Read-Host "Enter number of days in the future to check expiration dates (press enter to renew certificates expired through today)" If ([string]::IsNullOrWhiteSpace($DaysOffset)) { $DaysOffset = 0 } } else { $DaysOffset = 0 } #Additional confirmations along the way $ConfirmEachCertificateChoice = $host.ui.PromptForChoice("Confirm each certificate before proceeding?","Please select yes or no",[System.Management.Automation.Host.ChoiceDescription[]]("&Yes","&No"),0) Switch ($ConfirmEachCertificateChoice) { 0 {$ConfirmEachCertificate = $true} 1 {$ConfirmEachCertificate = $false} } #Get all certificates $Certificates = Get-NcSecurityCertificate #Process each certificate one by one ForEach ($Certificate in $Certificates) { Write-Host "" Write-Host "*************************************************************************************" #Get values $CertificateAuthority = $Certificate.CertificateAuthority $CommonName = $Certificate.CommonName $Country = $Certificate.Country $EmailAddress = $Certificate.EmailAddress $ExpirationDate = $Certificate.ExpirationDate $ExpirationDateDT = $Certificate.ExpirationDateDT $ExpirationDateSpecified = $Certificate.ExpirationDateSpecified $ExpireDays = $Certificate.ExpireDays $ExpireDaysSpecified = $Certificate.ExpireDaysSpecified $HashFunction = $Certificate.HashFunction $Locality = $Certificate.Locality $NcController = $Certificate.NcController $Organization = $Certificate.Organization $OrganizationUnit = $Certificate.OrganizationUnit $Protocol = $Certificate.Protocol $PublicCertificate = $Certificate.PublicCertificate $SerialNumber = $Certificate.SerialNumber $Size = $Certificate.Size $StartDate = $Certificate.StartDate $StartDateDT = $Certificate.StartDateDT $StartDateSpecified = $Certificate.StartDateSpecified $State = $Certificate.State $Type = $Certificate.Type $Vserver = $Certificate.Vserver $VserverPlusCertExtension = $Vserver+".cert" Write-Host "Working with certificate" $CommonName "on SVM" $Vserver "with serial number" $SerialNumber #Make sure certificate is self-signed by checking the certificate authority is equal to the vserver If ($CommonName -eq $CertificateAuthority) { $IsSelfSignedCertificate = $true } else { $IsSelfSignedCertificate = $False } #Only work with server type and ignore other types If ($Type -eq "server") { #Must be self signed If ($IsSelfSignedCertificate) { #Check if this is 8.3+ and if this is a node specific certificate If (($NumberOfNodes -ne 1 -and $Nodes -contains $Vserver) -or ($NumberOfNodes -eq 1 -and $Nodes.Node -eq $Vserver)) { Write-Host "In ONTAP" $FullONTAPVersion "node certificates are no longer needed. Reference https://kb.netapp.com/support/index?page=content&id=2024831&locale=en_US&access=s" -ForegroundColor Yellow $ProceedWithNodeCertificateRemovalChoice = $host.ui.PromptForChoice("Proceed with removing of no longer needed node certificate?","Please select yes or no",[System.Management.Automation.Host.ChoiceDescription[]]("&Yes","&No"),0) Switch ($ProceedWithNodeCertificateRemovalChoice) { 0 {$ProceedWithNodeCertificateRemoval = $true} 1 {$ProceedWithNodeCertificateRemoval = $false} } If ($ProceedWithNodeCertificateRemoval) { #Remove node certificate that is no longer needed $QueryCertificate = Get-NcSecurityCertificate -Template $QueryCertificate = $Certificate $error.clear() $RemoveCertificate = Remove-NcSecurityCertificate -Query $QueryCertificate -Confirm:$False -ErrorAction SilentlyContinue If ($RemoveCertificate.SuccessCount -eq 1) { Write-Host "Removed certificate" $CommonName "on SVM" $Vserver -ForegroundColor Green } else { Write-Host "Removing certificate" $CommonName "on SVM" $Vserver "has failed. See error below." -ForegroundColor Red write-host $error -ForegroundColor Red Continue } } Continue } #Check date on certificate for expiration If ((($ExpirationDateDT) -le $CurrentDate.AddDays($DaysOffset)) -or $RenewNonExpiredCertificates) { #Ask if required If ($ConfirmEachCertificate) { $ProceedCertificateRenewalChoice = $host.ui.PromptForChoice("Proceed with recreating certificate $CommonName on SVM $Vserver now?","Please select yes or no",[System.Management.Automation.Host.ChoiceDescription[]]("&Yes","&No"),0) Switch ($ProceedCertificateRenewalChoice) { 0 {$ProceedCertificateRenewal = $true} 1 {$ProceedCertificateRenewal = $false} } } If ($ProceedCertificateRenewal) { #Get SSL configuration for the SVM $CurrentSSLConfiguration = Get-NcSecuritySsl -VserverContext $Vserver $SSLConfigurationCertificateAuthority = $CurrentSSLConfiguration.CertificateAuthority $SSLConfigurationCertificateSerialNumber = $CurrentSSLConfiguration.CertificateSerialNumber $SSLConfigurationClientAuthenticationEnabled = $CurrentSSLConfiguration.ClientAuthenticationEnabled $SSLConfigurationCommonName = $CurrentSSLConfiguration.CommonName $SSLConfigurationNcController = $CurrentSSLConfiguration.NcController $SSLConfigurationServerAuthenticationEnabled = $CurrentSSLConfiguration.ServerAuthenticationEnabled $SSLConfigurationVserver = $CurrentSSLConfiguration.Vserver $SSLConfigurationClientAuthenticationEnabled = $CurrentSSLConfiguration.ClientAuthenticationEnabled $SSLConfigurationServerAuthenticationEnabled = $CurrentSSLConfiguration.ServerAuthenticationEnabled $CommonNameCount = Get-NcSecurityCertificate | Where-Object {$_.CommonName -eq $CommonName} If ($CommonNameCount.length -gt 1) { Write-Host "More than one certificate exists with the common name of" $CommonName "on SVM" $Vserver "therefore not proceeding with SSL configuration until only a single certificate exists with that common name." -ForegroundColor Red Continue } #Unique serial numbers must match between the SVM SSL configuration and the certificate If ($SSLConfigurationCertificateSerialNumber -eq $Certificate.SerialNumber) { #Remove certificate $error.clear() $RemoveCertificate = Remove-NcSecurityCertificate -Query $Certificate -Confirm:$False -ErrorAction SilentlyContinue If ($RemoveCertificate.SuccessCount -eq 1) { Write-Host "Removed certificate" $CommonName "on SVM" $Vserver -ForegroundColor Green } else { Write-Host "Removing certificate" $CommonName "on SVM" $Vserver "has failed. See error below." -ForegroundColor Red write-host $error -ForegroundColor Red #Continue } $error.clear() #Create certificate $CreateCertificate = New-NcSecurityCertificate -CommonName $CommonName -Type $Type -Size $Size ` -Country $Country -State $State -Locality $Locality -Organization $Organization ` -OrganizationUnit $OrganizationUnit -EmailAddress $EmailAddress -HashFunction $HashFunction ` -Vserver $Vserver -ExpireDays $NewCertificateExpireDays -Confirm:$False -ErrorAction SilentlyContinue -ErrorVariable CreateCertificateFailed If (!$CreateCertificateFailed) { If ($CreateCertificate.count -eq 1) { #Get variables to configure SVM SSL later $RecreatedCertificateSerialNumber = $CreateCertificate.SerialNumber.ToString() $RecreatedCertificateCommonName = $CreateCertificate.CommonName.ToString() $RecreatedCertificateCertificateAuthority = $CreateCertificate.CertificateAuthority.ToString() Write-Host "Recreated certificate" $CommonName "on SVM" $Vserver "with new expiration date of" $CreateCertificate.ExpirationDateDT -ForegroundColor Green } else { Write-Host "More than one certificate exists with the common name of" $CommonName "on SVM" $Vserver "therefore not proceeding with SSL configuration until only a single certificate exists with that common name." -ForegroundColor Red Continue } } else { Write-Host "Recreating certificate" $CommonName "on SVM" $Vserver "has failed. See error below." -ForegroundColor Red write-host $error -ForegroundColor Red Continue } $error.clear() #Configure SSL for new certificate If ($FamilyRelease -eq 9) { #workaround for bug in PowerShell toolkit specific to the Set-NcSecuritySsl cmdlet $APIRequest = " ` $SSLConfigurationVserver ` $RecreatedCertificateCertificateAuthority ` $RecreatedCertificateCommonName ` $SSLConfigurationServerAuthenticationEnabled ` $SSLConfigurationClientAuthenticationEnabled ` $RecreatedCertificateSerialNumber ` " $ConfiguredSSL = Invoke-NcSystemApi -VserverContext $SSLConfigurationVserver ` -Request $APIRequest -ErrorAction SilentlyContinue -ErrorVariable ConfiguredSSLFailed If (!$ConfiguredSSLFailed) { Write-Host "Reconfigured SSL on SVM" $Vserver "to work with recreated certificate" $RecreatedCertificate.CommonName -ForegroundColor Green } else { Write-Host "Reconfiguring SSL on SVM" $Vserver "to work with recreated certificate" $RecreatedCertificate.CommonName "has failed. See error below." -ForegroundColor Red write-host $error -ForegroundColor Red Continue } } else { #8.3 only command $ConfiguredSSL = Set-NcSecuritySsl -Vserver $SSLConfigurationVserver ` -CertificateAuthority $RecreatedCertificate.CertificateAuthority ` -CertificateSerialNumber $RecreatedCertificateSerialNumber ` -CommonName $RecreatedCertificateCommonName ` -EnableServerAuthentication $SSLConfigurationServerAuthenticationEnabled ` -EnableClientAuthentication $SSLConfigurationClientAuthenticationEnabled ` -Confirm:$False -ErrorAction SilentlyContinue -ErrorVariable ConfiguredSSLFailed If (!$ConfiguredSSLFailed) { Write-Host "Reconfigured SSL on SVM" $Vserver "to work with recreated certificate" $RecreatedCertificate.CommonName -ForegroundColor Green } else { Write-Host "Reconfiguring SSL on SVM" $Vserver "to work with recreated certificate" $RecreatedCertificate.CommonName "has failed. See error below." -ForegroundColor Red write-host $error -ForegroundColor Red Continue } } $error.clear() } else { Write-Host "This certificate is currently not in use for SSL configuration. Not recreating." -ForegroundColor Yellow } } else { Write-Host "Not processing certificate" $CommonName "on SVM" $Vserver "based upon choice." -ForegroundColor Yellow } } else { Write-Host "Certificate" $CommonName "has not expired and will not be renewed." } } else { Write-Host "Certificate" $CommonName "is not a self-signed certificate and must be renewed through your external certificate authority." -ForegroundColor Yellow } } else { Write-Host "Certificate" $CommonName "is not a server type certificate and does not need to be processed." } } } else { Write-Host "This script is only available for ONTAP 8.3+ systems." -ForegroundColor Red } #endregion