NetAppSSLCertificateRenew.ps1
<#
.NOTES File Name: NetAppSSLCertificateRenew.ps1 .COMPONENT -NetApp PowerShell Toolkit: https://www.powershellgallery.com/packages/NetApp.ONTAP .SYNOPSIS Version: 1.6 - Changed the script file name for publishing Moved to using current NetApp.ONTAP module Simplified connection to cluster Execute only on ONTAP 9.x clusters Moved deletion of previous certificate to end of creation of new one and configuring of SSL 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: "This operation is not permitted on a Vserver that is configured as the destination for identity preserve Vserver DR." No actual certificate changes are made for this SVM DR destination. -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 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/Advice_and_Troubleshooting/Data_Storage_Software/ONTAP_OS/How_to_renew_a_Self-Signed_SSL_certificate_in_ONTAP_9 This script handles the steps outlined in the article by doing the following: 1) Connecting to a cluster 2) Collecting all existing certificates 3) Ensuring the certificate is self-signed 4) Creates a new certificate with the same properties as the previous one with a 10 year expiration 5) Configures SSL on the SVM to use the new certificate 6) Deletes the previous self-signed 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 .\NetAppSSLCertificateRenew.ps1 Running without any parameters will prompt for all necessary values .EXAMPLE .\NetAppSSLCertificateRenew.ps11 -Cluster NetApp1 -Username admin -Password MyPassword Connects to the cluster named NetApp1 with the provided credentials. #> <#PSScriptInfo .VERSION 1.6 .GUID f1e1fe83-68bb-4c90-88c1-5f671104105e .AUTHOR mcgue .COMPANYNAME .COPYRIGHT .TAGS .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES NetApp.ONTAP .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .PRIVATEDATA #> <# .DESCRIPTION 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/Advice_and_Troubleshooting/Data_Storage_Software/ONTAP_OS/How_to_renew_a_Self-Signed_SSL_certificate_in_ONTAP_9 This script handles the steps outlined in the article by doing the following: 1) Connecting to a cluster 2) Collecting all existing certificates 3) Ensuring the certificate is self-signed 4) Creates a new certificate with the same properties as the previous one with a 10 year expiration 5) Configures SSL on the SVM to use the new certificate 6) Deletes the previous self-signed certificate #> #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 If (-Not (Get-Module NetApp.ONTAP)) { Import-Module NetApp.ONTAP } #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 = "" } If ($Password.Length -eq 0) { $SecurePassword = "" } else { $SecurePassword = New-Object -TypeName System.Security.SecureString $Password.ToCharArray() | ForEach-Object {$SecurePassword.AppendChar($_)} } #Preparing credential object to pass If ($Username.Length -ne 0 -and $SecurePassword.Length -ne 0) { $Credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $Username, $SecurePassword } else { $Credentials = $Username } Write-Host "Attempting connection to $Cluster" # 1) Connecting to a 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 $Found9Plus = $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] #Only run in ONTAP 9 since that is the only supported release If ($FamilyRelease -eq 9) { $Found9Plus = $true } #Only continue of version of ONTAP is at least 9.0 If ($Found9Plus) { #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} } # 2) Collecting all existing 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 # 3) Ensuring the certificate is self-signed #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) { $error.clear() # 4) Creates a new certificate with the same properties as the previous one with a 10 year expiration $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) { #When New-NcSecurityCertificate it returns an object containing all certificates that match the common name, and since the previous certificate is not deleted we have to filter out the previous serial number $NewCreateCertificate = $CreateCertificate | Where-Object {$_.SerialNumber -ne $SerialNumber} If ($NewCreateCertificate.count -eq 1) { #Get variables to configure SVM SSL later $RecreatedCertificateSerialNumber = $NewCreateCertificate.SerialNumber.ToString() $RecreatedCertificateCommonName = $NewCreateCertificate.CommonName.ToString() $RecreatedCertificateCertificateAuthority = $NewCreateCertificate.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() # 5) Configures SSL on the SVM to use the new certificate #workaround for bug in PowerShell toolkit specific to the Set-NcSecuritySsl cmdlet $APIRequest = "<security-ssl-modify> ` <vserver>$SSLConfigurationVserver</vserver> ` <certificate-authority>$RecreatedCertificateCertificateAuthority</certificate-authority> ` <common-name>$RecreatedCertificateCommonName</common-name> ` <server-authentication-enabled>$SSLConfigurationServerAuthenticationEnabled</server-authentication-enabled> ` <client-authentication-enabled>$SSLConfigurationClientAuthenticationEnabled</client-authentication-enabled> ` <certificate-serial-number>$RecreatedCertificateSerialNumber</certificate-serial-number> ` </security-ssl-modify>" $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 } # 6) Deletes the previous self-signed 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 } } 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 9.0+ systems." -ForegroundColor Red } #endregion |