518 lines
22 KiB
PowerShell
518 lines
22 KiB
PowerShell
Configuration SenseSetup {
|
|
# Load required modules
|
|
Import-DscResource -ModuleName PSDesiredStateConfiguration, QlikResources #, xSmbShare, CitiClarity
|
|
|
|
# Configuration for all nodes
|
|
Node $AllNodes.NodeName {
|
|
LocalConfigurationManager
|
|
{
|
|
CertificateId = Get-PfxCertificate $Node.CertificateFile
|
|
ConfigurationMode = 'ApplyOnly'
|
|
RebootNodeIfNeeded = $false
|
|
}
|
|
|
|
# Ensure service account is in local Administrators group prior to install of Sense
|
|
$ServiceUsername = $Node.ServiceAccount.UserName
|
|
Script AdministratorsGroup {
|
|
TestScript = {
|
|
$IsMember = (Get-LocalGroupMember -Name Administrators).Name -contains $using:ServiceUsername
|
|
if (Test-Path "$env:ProgramFiles\Qlik\Sense") {
|
|
return (-Not $IsMember)
|
|
} else {
|
|
return $IsMember
|
|
}
|
|
}
|
|
SetScript = {
|
|
if (Test-Path "$env:ProgramFiles\Qlik\Sense") {
|
|
Remove-LocalGroupMember `
|
|
-Name 'Administrators' `
|
|
-Member $using:ServiceUsername
|
|
} else {
|
|
Add-LocalGroupMember `
|
|
-Name 'Administrators' `
|
|
-Member $using:ServiceUsername
|
|
}
|
|
}
|
|
GetScript = {
|
|
@{ Result = (Get-LocalGroupMember -Name Administrators) }
|
|
}
|
|
}
|
|
|
|
# Ensure 'High performance' power profile is active
|
|
Windows PowerPolicy {
|
|
PowerScheme = '8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c'
|
|
}
|
|
|
|
# Ensure pagefile size is set to 3GB for initial and max settings
|
|
PageFile Local {
|
|
InitialSize = 3072
|
|
MaximumSize = 3072
|
|
}
|
|
|
|
if ($Node.ProxyCert) {
|
|
CertificateImport Proxy {
|
|
Username = $Node.Node.ServiceAccount.Username
|
|
Permission = 'ReadAndExecute'
|
|
StoreLocation = 'LocalMachine\My'
|
|
FilePath = $Node.ProxyCert
|
|
Password = $CertificatePassword
|
|
}
|
|
}
|
|
}
|
|
|
|
# Node $AllNodes.Where{$_.Role -eq 'Scheduler'}.Nodename {
|
|
# $CentralNode = $AllNodes.Where{$_.Role -eq 'Central'}.NodeName
|
|
|
|
# # Skip kerberos if the installer doesn't exist
|
|
# if (Test-Path "\\$CentralNode\Clarity\Install\kfw-4.1-amd64.msi") {
|
|
# Package Kerberos {
|
|
# Name = 'MIT Kerberos for Windows (64-bit) 4.1.0'
|
|
# Path = "\\$CentralNode\Clarity\Install\kfw-4.1-amd64.msi"
|
|
# ProductId = '{AF6E168F-F6FE-4728-8F6E-E3E68F5C1FD3}'
|
|
# Credential = $Node.ServiceAccount
|
|
# Ensure = 'Present'
|
|
# }
|
|
|
|
# File krb5.ini {
|
|
# SourcePath = "\\$CentralNode\Clarity\Install\krb5.ini"
|
|
# DestinationPath = "$env:PROGRAMDATA\MIT\Kerberos5\krb5.ini"
|
|
# Type = 'File'
|
|
# Checksum = 'SHA-1'
|
|
# Ensure = 'Present'
|
|
# Credential = $Node.ServiceAccount
|
|
# DependsOn = '[Package]Kerberos'
|
|
# }
|
|
|
|
# File keytab {
|
|
# SourcePath = "\\$CentralNode\Clarity\Install\all_keytabs_prod"
|
|
# DestinationPath = "D:\all_keytabs_prod"
|
|
# Type = 'Directory'
|
|
# Checksum = 'SHA-1'
|
|
# MatchSource = $true
|
|
# Ensure = 'Present'
|
|
# Credential = $Node.ServiceAccount
|
|
# DependsOn = '[Package]Kerberos'
|
|
# }
|
|
# }
|
|
|
|
# # Skip Cloudera if installer doesn't exist
|
|
# if (Test-Path "\\$CentralNode\Clarity\Install\ClouderaImpalaODBC64.msi") {
|
|
# Package Cloudera {
|
|
# Name = 'Cloudera ODBC Driver for Impala'
|
|
# Path = "\\$CentralNode\Clarity\Install\ClouderaImpalaODBC64.msi"
|
|
# ProductId = '{111ADFD9-99CC-4695-8F48-44A5B397249D}'
|
|
# Credential = $Node.ServiceAccount
|
|
# Ensure = 'Present'
|
|
# }
|
|
|
|
# # Create ODBC DSN for Cloudera
|
|
# OdbcDsn Cloudera {
|
|
# DsnName = 'Impala PROD'
|
|
# DsnType = 'System'
|
|
# DriverName = 'Cloudera ODBC Driver for Impala'
|
|
# Platform = '64-Bit'
|
|
# Attribute = @{
|
|
# AllowHostNameCNMismatch = "0"
|
|
# AllowSelfSignedServerCert = "0"
|
|
# AsyncExecPollInterval = "10"
|
|
# AuthMech = "1"
|
|
# AutoReconnect = "1"
|
|
# CurrentSchemaRestrictedMetadata = "0"
|
|
# DefaultKeytabFile = "D:\all_keytabs_prod\pbgxsprd_dsccr001d01i1p.eur.nsroot.net.keytab"
|
|
# DelegateKrbCreds = "0"
|
|
# DelegationUID = ""
|
|
# DESCRIPTION = ""
|
|
# EnableSimulatedTransactions = "0"
|
|
# Host = "dsccr001d01i1p.eur.nsroot.net"
|
|
# KrbFQDN = "dsccr001d01i1p.eur.nsroot.net"
|
|
# KrbRealm = "EURUXPROD.DYN.NSROOT.NET"
|
|
# KrbServiceName = "impala"
|
|
# Port = "21050"
|
|
# RowsFetchedPerBlock = "10000"
|
|
# Schema = ""
|
|
# ServicePrincipalCanonicalization = "0"
|
|
# SocketTimeout = "30"
|
|
# SSL = "0"
|
|
# StringColumnLength = "32767"
|
|
# TrustedCerts = "C:\Program Files\Cloudera ODBC Driver for Impala\lib\cacerts.pem"
|
|
# TSaslTransportBufSize = "1000000"
|
|
# UID = "pbgxsprd/dsccr001d01i1p.eur.nsroot.net"
|
|
# UPNKeytabMappingFile = ""
|
|
# UseKeytab = "1"
|
|
# UseNativeQuery = "0"
|
|
# UseOnlySSPI = "0"
|
|
# UseSASL = "1"
|
|
# UseSQLUnicodeTypes = "0"
|
|
# UseSystemTrustStore = "0"
|
|
# LCaseSspKeyName = ""
|
|
# CheckCertRevocation = "1"
|
|
# }
|
|
# DependsOn = '[Package]Cloudera'
|
|
# }
|
|
# }
|
|
# }
|
|
|
|
# Configuration for Central node only
|
|
Node $AllNodes.Where{$_.Role -eq 'Central'}.NodeName {
|
|
NTFSAccess QlikProgramData {
|
|
Path = "$env:ProgramData\Qlik"
|
|
Permission = 'FullControl'
|
|
Username = $Node.ServiceAccount.Username
|
|
}
|
|
|
|
File QlikClusterRoot
|
|
{
|
|
Type = 'Directory'
|
|
DestinationPath = $ClusterLocalPath
|
|
Ensure = 'Present'
|
|
}
|
|
|
|
NTFSAccess QlikClusterRoot {
|
|
Path = $ClusterLocalPath
|
|
Permission = 'FullControl'
|
|
Username = $Node.ServiceAccount.Username
|
|
}
|
|
|
|
$ConfigurationData.NonNodeData.Shares.Cluster.Full.ForEach{
|
|
NTFSAccess "QlikClusterRoot-$($_)" {
|
|
Path = $ClusterLocalPath
|
|
Permission = 'FullControl'
|
|
Username = $_
|
|
}
|
|
}
|
|
|
|
# xSmbShare QlikClusterShare
|
|
# {
|
|
# Path = $ClusterLocalPath
|
|
# Name = 'Clarity'
|
|
# FullAccess = @($ConfigurationData.NonNodeData.Shares.Cluster.Full |?{$_}) +
|
|
# $Node.ServiceAccount.GetNetworkCredential().UserName
|
|
# Ensure = 'Present'
|
|
# DependsOn = '[File]QlikClusterRoot'
|
|
# }
|
|
|
|
# Install Sense as a Central node
|
|
QlikPackage Central
|
|
{
|
|
Name = $ConfigurationData.NonNodeData.Sense.ReleaseName
|
|
Setup = "$ClusterLocalPath\Install\Qlik_Sense_setup.exe"
|
|
Patch = "$(if(Test-Path "$ClusterLocalPath\Install\Qlik_Sense_update.exe"){"$ClusterLocalPath\Install\Qlik_Sense_update.exe"})"
|
|
ServiceCredential = $Node.ServiceAccount
|
|
RootDir = "\\$($Node.Hostname)\Clarity"
|
|
DbSuperUserPassword = $DbRepoUser
|
|
DbCredential = $DbRepoUser
|
|
CreateCluster = $true
|
|
InstallLocalDb = $true
|
|
ConfigureDbListener = $true
|
|
Hostname = $Node.Hostname
|
|
ConfigureLogging = $true
|
|
SetupLocalLoggingDb = $true
|
|
QLogsWriterPassword = $DbRepoUser
|
|
QLogsReaderPassword = $DbRepoUser
|
|
QLogsHostname = $Node.Hostname
|
|
QLogsPort = 4432
|
|
Ensure = 'Present'
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
DependsOn = '[NTFSAccess]QlikProgramData', '[xSmbShare]QlikClusterShare'
|
|
}
|
|
|
|
# Ensure QRD service is set for manual startup
|
|
# and is running as Sense service account
|
|
xService QRD {
|
|
Name = 'QlikSenseRepositoryDatabase'
|
|
StartupType = 'Manual'
|
|
State = 'Running'
|
|
Credential = $Node.ServiceAccount
|
|
DependsOn = '[QlikPackage]Central'
|
|
}
|
|
|
|
xService QRS {
|
|
Name = 'QlikSenseRepositoryService'
|
|
StartupType = 'Manual'
|
|
State = 'Running'
|
|
DependsOn = '[xService]QRD'
|
|
}
|
|
|
|
QlikConnect SenseCentral
|
|
{
|
|
Computername = $Node.Hostname
|
|
Username = $Node.AdminAccount.UserName
|
|
TrustAllCerts = $true
|
|
RetryDelay = 15
|
|
MaxRetries = 40
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
DependsOn = '[xService]QRS'
|
|
}
|
|
|
|
QlikLicense SiteLicense
|
|
{
|
|
Serial = $ConfigurationData.NonNodeData.Sense.License.Serial
|
|
Control = $ConfigurationData.NonNodeData.Sense.License.Control
|
|
Name = $ConfigurationData.NonNodeData.Sense.License.Name
|
|
Organization = $ConfigurationData.NonNodeData.Sense.License.Organization
|
|
Lef = $ConfigurationData.NonNodeData.Sense.License.Lef
|
|
Ensure = "Present"
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
DependsOn = "[QlikConnect]SenseCentral"
|
|
}
|
|
|
|
# Ensure accounts listed in the environment data file are RootAdmin
|
|
$ConfigurationData.NonNodeData.Sense.RootAdmin.foreach{
|
|
QlikUser $_ {
|
|
UserId = $_.Substring($_.IndexOf('\') + 1)
|
|
UserDirectory = $_.Substring(0, $_.IndexOf('\'))
|
|
Roles = 'RootAdmin'
|
|
Ensure = 'Present'
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
DependsOn = '[QlikLicense]SiteLicense'
|
|
}
|
|
}
|
|
|
|
SenseCertificate Windows {
|
|
MachineName = $Node.NodeName
|
|
Password = $certPassword
|
|
IncludeSecretKey = $true
|
|
ExportFormat = 'Windows'
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
DependsOn = '[QlikLicense]SiteLicense'
|
|
}
|
|
|
|
SenseCertificate Pem {
|
|
MachineName = $Node.NodeName
|
|
Password = $certPassword
|
|
IncludeSecretKey = $true
|
|
ExportFormat = 'Pem'
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
DependsOn = '[QlikLicense]SiteLicense'
|
|
}
|
|
|
|
# Copy Sense server certificate to PostgreSQL directory
|
|
File Postgres_cert {
|
|
SourcePath = "$env:PROGRAMDATA\Qlik\Sense\Repository\Exported Certificates\.Local Certificates\server.pem"
|
|
DestinationPath = "$env:PROGRAMDATA\Qlik\Sense\Repository\PostgreSQL\9.6\server.pem"
|
|
Type = 'File'
|
|
Ensure = 'Present'
|
|
DependsOn = '[xService]QRS'
|
|
}
|
|
|
|
# Copy Sense server key to PostgreSQL directory
|
|
File Postgres_key {
|
|
SourcePath = "$env:PROGRAMDATA\Qlik\Sense\Repository\Exported Certificates\.Local Certificates\server_key.pem"
|
|
DestinationPath = "$env:PROGRAMDATA\Qlik\Sense\Repository\PostgreSQL\9.6\server_key.pem"
|
|
Type = 'File'
|
|
Ensure = 'Present'
|
|
DependsOn = '[xService]QRS'
|
|
}
|
|
|
|
# Ensure SSL settings are configured in postgresql.conf
|
|
# and max connections is set to node count * 100
|
|
# Ensure Postgres access control is configured for SSL only
|
|
Postgres Local {
|
|
SSL = $true
|
|
SSLCiphers = 'DEFAULT:!LOW:!EXP:!eNULL:!aNULL:!MD5:!RC2:!RC4:!DES:@STRENGTH'
|
|
CertFile = 'server.pem'
|
|
KeyFile = 'server_key.pem'
|
|
MaxConnections = $AllNodes.Count * 100
|
|
HostAccess = @(
|
|
'hostssl all all all md5',
|
|
'host all all all md5'
|
|
)
|
|
IdleTransactionTimeout = '5min'
|
|
Credential = $DbSuperUser
|
|
DependsOn = '[File]Postgres_cert', '[File]Postgres_key'
|
|
}
|
|
}
|
|
|
|
# Configuration for Rim nodes only (not Central)
|
|
Node $AllNodes.Where{$_.Role -ne 'Central'}.NodeName {
|
|
$CentralNode = $AllNodes.Where{$_.Role -eq 'Central'}.Hostname
|
|
|
|
# Copy setup file to local disk
|
|
File SenseSetup {
|
|
SourcePath = "\\$CentralNode\Clarity\Install\Qlik_Sense_setup.exe"
|
|
DestinationPath = "C:\Install\Qlik_Sense_setup.exe"
|
|
Type = 'File'
|
|
Checksum = 'SHA-1'
|
|
Ensure = 'Present'
|
|
Credential = $Node.ServiceAccount
|
|
}
|
|
|
|
# If patch file exists copy it to local disk
|
|
if (Test-Path "$ClusterLocalPath\Install\Qlik_Sense_update.exe") {
|
|
$SenseUpdate = "C:\Install\Qlik_Sense_update.exe"
|
|
File SenseUpdate {
|
|
SourcePath = "\\$CentralNode\Clarity\Install\Qlik_Sense_update.exe"
|
|
DestinationPath = $SenseUpdate
|
|
Type = 'File'
|
|
Checksum = 'SHA-1'
|
|
Ensure = 'Present'
|
|
Credential = $Node.ServiceAccount
|
|
}
|
|
}
|
|
|
|
# Pause execution if central node is not ready
|
|
WaitForSense $CentralNode {
|
|
ComputerName = $CentralNode
|
|
RetryDelay = 60
|
|
MaxRetries = 30
|
|
SkipVerify = $true
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
}
|
|
|
|
# Install Qlik Sense as Rim node
|
|
# and join existing cluster (including registering with Central)
|
|
QlikRimNode $Node.NodeName {
|
|
SenseService = $Node.ServiceAccount
|
|
ProductName = $ConfigurationData.NonNodeData.Sense.ReleaseName
|
|
SetupPath = 'C:\Install\Qlik_Sense_setup.exe'
|
|
PatchPath = $SenseUpdate
|
|
Hostname = $Node.Hostname
|
|
Name = $Node.Name
|
|
CentralNode = $CentralNode
|
|
DbCredential = $DbRepoUser
|
|
Engine = ($Node.Role -match 'Engine' -or $Node.Role -eq 'Scheduler')
|
|
Printing = ($Node.Role -match 'Engine')
|
|
Proxy = ($Node.Role -match 'Proxy')
|
|
Scheduler = ($Node.Role -eq 'Scheduler')
|
|
ManageServices = $false
|
|
ManageFirewall = $false
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
DependsOn = @("[WaitForSense]$CentralNode", '[File]SenseSetup') + $(if($SenseUpdate){'[File]SenseUpdate'})
|
|
}
|
|
}
|
|
|
|
# Configuration for all nodes
|
|
Node $AllNodes.NodeName {
|
|
# Ensure Sense program data is shared as Sense
|
|
# with access levels defined in environment data file
|
|
xSmbShare Sense {
|
|
Path = "$env:ProgramData\Qlik\Sense"
|
|
Name = 'Sense'
|
|
FullAccess = @($ConfigurationData.NonNodeData.Shares.Sense.Full |?{$_}) +
|
|
$Node.ServiceAccount.GetNetworkCredential().UserName
|
|
ReadAccess = $ConfigurationData.NonNodeData.Shares.Sense.Read
|
|
Ensure = 'Present'
|
|
DependsOn = if($Node.Role -eq 'Central'){'[Postgres]Local'}else{"[QlikRimNode]$($Node.Nodename)"}
|
|
}
|
|
|
|
Group SenseServiceUsers {
|
|
GroupName = 'Qlik Sense Service Users'
|
|
MembersToInclude = $Node.ServiceAccount.UserName
|
|
PsDscRunAsCredential = $Node.AdminAccount
|
|
DependsOn = '[xSmbShare]Sense'
|
|
}
|
|
|
|
Group PerfMonUsers {
|
|
GroupName = 'Performance Monitor Users'
|
|
MembersToInclude = $Node.ServiceAccount.UserName
|
|
PsDscRunAsCredential = $Node.AdminAccount
|
|
DependsOn = '[xSmbShare]Sense'
|
|
}
|
|
|
|
# Delete the examples directory as required by security audit
|
|
File Examples {
|
|
DestinationPath = 'C:\ProgramData\Qlik\Examples'
|
|
Type = 'Directory'
|
|
Ensure = 'Absent'
|
|
Force = $true
|
|
Credential = $Node.ServiceAccount
|
|
DependsOn = '[xSmbShare]Sense'
|
|
}
|
|
|
|
# Remove HTTP server header for DotNot web servers (Sense Proxy)
|
|
HTTP Server {
|
|
DisableServerHeader = 2
|
|
DependsOn = '[xSmbShare]Sense'
|
|
}
|
|
|
|
# Ensure all Sense services are configured for manual startup
|
|
@(
|
|
'QlikSenseEngineService',
|
|
'QlikSensePrintingService',
|
|
'QlikSenseProxyService',
|
|
'QlikSenseRepositoryService',
|
|
'QlikSenseSchedulerService',
|
|
'QlikSenseServiceDispatcher'
|
|
).ForEach{
|
|
xService $_ {
|
|
Name = $_
|
|
StartupType = 'Manual'
|
|
State = 'Running'
|
|
DependsOn = '[Group]SenseServiceUsers', '[Group]PerfMonUsers'
|
|
}
|
|
}
|
|
|
|
# Ensure Qlik logging service is stopped and disabled
|
|
xService QlikLogging {
|
|
Name = 'QlikLoggingService'
|
|
StartupType = 'Disabled'
|
|
State = 'Stopped'
|
|
DependsOn = '[xService]QlikSenseRepositoryService'
|
|
}
|
|
|
|
# Wait for Sense services to be ready by checking service status on central node
|
|
WaitForSense Repository {
|
|
ComputerName = $AllNodes.Where{$_.Role -eq 'Central'}.Hostname
|
|
Node = $Node.Hostname
|
|
MaxRetries = 20
|
|
RetryDelay = 30
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
DependsOn = '[xService]QlikSenseRepositoryService'
|
|
}
|
|
|
|
if($Node.ProxyCert) {
|
|
$Thumbprint = (Get-PfxData -FilePath $Node.ProxyCert).EndEntityCertificates.ThumbPrint
|
|
}
|
|
# Ensure SSL certificate thumbprint is configured for Proxy service
|
|
QlikProxy Local {
|
|
Node = $Node.Hostname
|
|
SslBrowserCertificateThumbprint = $Thumbprint
|
|
PsDscRunAsCredential = $Node.AdminAccount
|
|
DependsOn = '[WaitForSense]Repository'
|
|
}
|
|
|
|
# Ensure default virtual proxies are configured to load balance to engine nodes
|
|
# and host names defined in environment data file are in whitelist
|
|
QlikVirtualProxy Default {
|
|
Description = "$($Node.Name) Proxy (Default)"
|
|
Prefix = '/'
|
|
SessionCookieHeaderName = 'X-Qlik-Session'
|
|
LoadBalancingServerNodes = "engineEnabled eq true and schedulerEnabled eq false"
|
|
WebSocketCrossOriginWhitelist = $ConfigurationData.NonNodeData.Sense.HostWhitelist
|
|
AdditionalResponseHeaders = @"
|
|
X-XSS-Protection: 1
|
|
X-Frame-Options: deny
|
|
Content-Security-Policy: frame-ancestors 'none'
|
|
Strict-Transport-Security: max-age=86400; includeSubDomains
|
|
X-Content-Type-Options: nosniff
|
|
"@
|
|
Ensure = 'Present'
|
|
PsDscRunasCredential = $Node.AdminAccount
|
|
DependsOn = '[WaitForSense]Repository'
|
|
}
|
|
|
|
# Ensure QRS connection string is configured for SSL
|
|
# and is set to use TLS 1.2 only
|
|
# SenseRepository Postgres {
|
|
# SSLMode = 'Require'
|
|
# TLSProtocol = '1.3'
|
|
# PostgresCommandTimeout = 0
|
|
# DependsOn = '[WaitForSense]Repository'
|
|
# }
|
|
|
|
# $CentralNode = $AllNodes.Where{$_.Role -eq 'Central'}.NodeName
|
|
# $NodeSetup = @(Get-ChildItem "$ClusterLocalPath\Install\node-*.msi")[0].Name
|
|
# # Upgrade the version of node js used by the Sense service dispatcher
|
|
# if ($NodeSetup) {
|
|
# Package NodeJS {
|
|
# Name = 'Node.js'
|
|
# Path = "\\$CentralNode\Clarity\Install\$NodeSetup"
|
|
# ProductId = '{A6606125-61E2-43C3-BFCF-0E571EC56656}'
|
|
# Arguments = 'INSTALLDIR="C:\Program Files\Qlik\Sense\ServiceDispatcher\Node" REBOOT=ReallySuppress /norestart'
|
|
# Credential = $Node.ServiceAccount
|
|
# Ensure = 'Present'
|
|
# DependsOn = '[QlikProxy]Local', '[QlikVirtualProxy]Default'
|
|
# }
|
|
# }
|
|
}
|
|
} |