Need help setting up Google Cloud Directory Sync with AD using secure LDAP

10,238

Update Sept 23, 2020 Today I updated GCDS and the TLS stuff broke again. This time, the problem was with an inability to access our CRL file from an offline root CA. I found that Google has beefed up its help page for GCDS certificate problems here: https://support.google.com/a/answer/3075991 I found my solution there.

Update Jan 20, 2020: It is anticipated that with the March 2020 patches, Microsoft will disallow insecure binds. This answer is likely to gain some additional attention, as Google Cloud Directory Sync will likely then fail to connect to AD unless TLS is being used.

Original Answer

Google Cloud Directory Sync is a Java application. The GCDS installer installs a version of the Java run-time environment in a sub-folder. That installation has its own set of trusted root certificate authorities. It does not use the certs installed in Windows.

To get things working, you need to import the public certificate for the trusted Certificate Authority that issued the certificate being used by your domain controller. You could instead install the public certificate from your domain controller, but that certificate will likely expire much sooner than the issuing certificate authority's certificate.

Google provides instructions here: https://support.google.com/a/answer/3075991?hl=en However, their instructions use the DC's public certificate, not the CA's certificate.

Obtain the CA certificate. I'm going to call it the_cert.cer

If you're following Google's instructions, you're exporting the cert from the domain controller:

certutil -store My DomainController %TEMP%\the_cert.cer

But again, you're better off with the CA certificate.

Move the certificate to the GCDS host.

On the GCDS host

Change folders to the jre folder where GCDS is installed. For me it was:

cd "c:\Program Files\Google Cloud Directory Sync\jre"

Yours might be different depending on your environment.

Install the certificate into the Java keystore:

bin\keytool -keystore lib\security\cacerts -storepass changeit -import -file %TEMP%\the_cert.cer -alias pick_a_name_you_like

The keytool utility will prompt: Trust this certificate? [no]: Type yes and hit the Enter key.

Clean up:

del the_cert.cer

Now, going against my advice again and using the DC's cert, here's a complete script you could run via Task Scheduler to keep your certificate up-to-date on your domain controller, assuming you run GCDS on the same domain controller.

<#
  .SYNOPSIS
  Exports the bound AD LDAPS encryption certificate and imports it into
  Google Cloud Directory Sync's Java keystore, so that GCDS syncs will succeed.

  .DESCRIPTION
  Google Cloud Directory Sync runs on Java. Java maintains its own trusted keystore,
  separate from the host operating system. Often, this keystore grows stale when updates
  are neglected. Further, the keystore would never contain certificate information for
  self-signed or internally-distributed certificates.

  In order to make GCDS work with TLS using secure LDAPS binding, it is necessary to
  export your trusted certificate from the machine's certificate store and import it into
  the GCDS-bundled Java Runtime Environment's certificate store.

  This script assumes the DC being contacted resides on the same host as the GCDS installation.

  Given a ComputerName and Port, this script will connect to the named DC and determine the
  thumbprint of the certificate bound to the DC on the specific port.

  Using this thumbprint, the script then exports the certificate from the Local Computer's MY (Personal)
  certificate store. This does NOT include the private key, and therefore it's safe to do this.

  Next, the script deletes and re-imports the certificate into the JRE certificate store.

  .PARAMETER ComputerName
  Use the fully-qualified network name of the machine. We're assuming this is the same network name
  that will be used in GCDS to bind against the DC, and is also the CommonName represented in the certificate.

  .PARAMETER Port
  Usually this will be 636, but could be custom depending on your environment.

  .OUTPUTS
  Will list the thumbprint of the cert found and will show stderr and stdout of the keytool commands.
  Error handling could definitely be beefed up here.

  .EXAMPLE
  C:\PS> .\Update-JavaDomainControllerCertificate.ps1 -ComputerName my.domain.com -Port 636

#>

[CmdletBinding()]
param (
    [Parameter(Mandatory=$true)]
    [string]
    $ComputerName,

    [int]
    $Port = 636
)
$FilePath = "$($Env:TEMP)\adcert.crt"
$Certificate = $null
$TcpClient = New-Object -TypeName System.Net.Sockets.TcpClient
try {

    $TcpClient.Connect($ComputerName, $Port)
    $TcpStream = $TcpClient.GetStream()

    $Callback = { param($sender, $cert, $chain, $errors) return $true }

    $SslStream = New-Object -TypeName System.Net.Security.SslStream -ArgumentList @($TcpStream, $true, $Callback)
    try {

        $SslStream.AuthenticateAsClient('')
        $Certificate = $SslStream.RemoteCertificate

    } finally {
        $SslStream.Dispose()
    }

} finally {
    $TcpClient.Dispose()
}

if ($Certificate) {
    if ($Certificate -isnot [System.Security.Cryptography.X509Certificates.X509Certificate2]) {
        $Certificate = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $Certificate
    }
    Write-Output "Found Certificate:"
    Write-Output $Certificate
}

Export-Certificate -Cert $Certificate -Force -FilePath $FilePath | Out-Null

Set-Location -Path "C:\Program Files\Google Cloud Directory Sync\jre"

# Delete existing entry
& .\bin\keytool -keystore lib\security\cacerts -storepass changeit -delete -noprompt -alias $ComputerName 2>&1 | %{ "$_" }

# Add entry
& .\bin\keytool -keystore lib\security\cacerts -storepass changeit -importcert -noprompt -file $FilePath -alias $ComputerName 2>&1 | %{ "$_" }

Remove-Item -Path $FilePath -Force
Share:
10,238

Related videos on Youtube

Mike
Author by

Mike

Updated on September 18, 2022

Comments

  • Mike
    Mike over 1 year

    I wanted to see if anyone else has set up a Google Cloud Directory Sync (GCDS aka GADS) with their Active Directory over secure LDAP (LDAPS). We've been syncing over port 389 and I'd like to encrypt that connection, but when I switch to port 636 the connection fails.

    I am running the GCDS tool on a member server in my domain - is the connection that I'm trying to establish on port 636 going between Google's off-site servers and my DC, or is it between the GCDS tool and my DC? And even if it is between the GCDS tool and my DC, does it still require a 3rd party certificate or is a self-signed certificate sufficient because the software is being run on a domain-joined server? Should I run the program on a DC?

    If this is an issue where I need a 3rd party certificate, some guidance would be appreciated as I'm not particularly knowledgeable in certificates. Thanks!

  • Aaron Hudon
    Aaron Hudon almost 7 years
    You most likely have to tell it that it should use SSL on that port. (Not sure how todo that for the sync tool)
  • Mike
    Mike almost 7 years
    There's a dropdown that allows you to select LDAP or LDAP+SSL
  • summea
    summea almost 7 years
    @Mike I've been facing this same type of issue. Running Google Cloud Directory Sync on the Domain Controller itself might be one option, but for setups that may require a separation between the Domain Controller and other services, there ought to be a way to resolve this issue in order to use the LDAP+SSL option. I'm currently looking for more documentation on this...
  • Mike
    Mike almost 7 years
    After a conversation with Google, there really was no need to go the SSL route, especially because it would add significant slowdown to the sync and the tool and my DC are on the same secure network. Also, LDAPS has nothing to do with the issues we were having so it wasn't really worth the effort to figure it out. So yeah, you'll probably need to chat with Google to figure out how to get LDAPS working - sorry I don't have more info!
  • Mike
    Mike almost 7 years
    Since you actually answered my question, I'm awarding this as the answer - I'm trusting it actually works ;) I appreciate the write-up! I don't know if I'll end up changing as it seems like adding SSL incurs more overhead, but it's definitely worth knowing how to do it should we need to in the future.
  • designarti
    designarti almost 7 years
    Leaving the insecure endpoint available is a security no-no which I'm trying to eliminate. The July 2017 patches contain something of a nudge. See portal.msrc.microsoft.com/en-us/security-guidance/…
  • Mike
    Mike almost 7 years
    GCDS lives on the machine it's authenticating against, so unless someone is sniffing that particular computer (highly unlikely), I don't see a need to use SSL. Now, if i had to authenticate over an unsecured network, then I'd definitely use SSL.
  • designarti
    designarti almost 7 years
    Sure, as long as you've firewalled 389 so external systems cannot get to it, you should be generally OK.
  • Zoredache
    Zoredache over 4 years
    Do you really need to use the DC cert? Can't you install and trust the CA cert that generates the certs for your DCs?
  • designarti
    designarti over 4 years
    You're right. What Java needs to trust is the Certificate Authority.