Merge pull request #23358 from praphull-purohit/ldap-tls
Add TLS options to support GSuite org data ingestion via LDAP
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-ldap': patch
|
||||
---
|
||||
|
||||
Add TLS support to ingest GSuite LDAP data
|
||||
@@ -110,6 +110,18 @@ This is the URL of the targeted server, typically on the form
|
||||
`ldaps://ds.example.net` for SSL enabled servers or `ldap://ds.example.net`
|
||||
without SSL.
|
||||
|
||||
#### target.tls.keys
|
||||
|
||||
`keys` in TLS options specifies location of a file, that contains private keys
|
||||
to establish connection with your LDAP server, in PEM format. See an example
|
||||
for Google Secure LDAP Service below.
|
||||
|
||||
#### target.tls.certs
|
||||
|
||||
`certs` in TLS options specifies location of a file, that contains certificate
|
||||
chains to establish connection with your LDAP server, in PEM format. See an
|
||||
example for Google Secure LDAP Service below.
|
||||
|
||||
### bind
|
||||
|
||||
The bind block specifies how the plugin should bind (essentially, to
|
||||
@@ -374,3 +386,28 @@ catalog:
|
||||
rules:
|
||||
- allow: [User, Group]
|
||||
```
|
||||
|
||||
### Example configurations
|
||||
|
||||
#### Google Secure LDAP Service
|
||||
|
||||
To sync Google Workspace/Cloud Identity organization data to users and groups in backstage,
|
||||
you must [configure Secure LDAP Service](https://support.google.com/a/answer/9048516) first.
|
||||
|
||||
Once Secure LDAP Service is configured, you can enable TLS options in LDAP configuration,
|
||||
as mentioned below. `keys` and `certs` specify the location of files that are generated
|
||||
while configuring Secure LDAP Service above.
|
||||
|
||||
```yaml
|
||||
ldap:
|
||||
providers:
|
||||
- target: ldaps://ldap.google.com:636
|
||||
tls:
|
||||
rejectUnauthorized: false
|
||||
keys: '/var/secrets/tls/gldap.key'
|
||||
certs: '/var/secrets/tls/gldap.crt'
|
||||
users:
|
||||
# users configuration comes here
|
||||
groups:
|
||||
# groups configuration comes here
|
||||
```
|
||||
|
||||
@@ -197,6 +197,8 @@ export function readLdapOrg(
|
||||
// @public
|
||||
export type TLSConfig = {
|
||||
rejectUnauthorized?: boolean;
|
||||
keys?: string;
|
||||
certs?: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
"@backstage/plugin-catalog-common": "workspace:^",
|
||||
"@backstage/plugin-catalog-node": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"@types/ldapjs": "^2.2.0",
|
||||
"ldapjs": "^2.2.0",
|
||||
"@types/ldapjs": "^2.2.5",
|
||||
"ldapjs": "^2.3.3",
|
||||
"lodash": "^4.17.21",
|
||||
"uuid": "^9.0.0",
|
||||
"winston": "^3.2.1"
|
||||
|
||||
@@ -15,16 +15,18 @@
|
||||
*/
|
||||
|
||||
import { ForwardedError, stringifyError } from '@backstage/errors';
|
||||
import { readFile } from 'fs/promises';
|
||||
import ldap, { Client, SearchEntry, SearchOptions } from 'ldapjs';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import tlsLib from 'tls';
|
||||
import { Logger } from 'winston';
|
||||
import { BindConfig, TLSConfig } from './config';
|
||||
import { createOptions, errorString } from './util';
|
||||
import {
|
||||
AEDirVendor,
|
||||
ActiveDirectoryVendor,
|
||||
DefaultLdapVendor,
|
||||
FreeIpaVendor,
|
||||
AEDirVendor,
|
||||
LdapVendor,
|
||||
} from './vendors';
|
||||
|
||||
@@ -44,9 +46,22 @@ export class LdapClient {
|
||||
bind?: BindConfig,
|
||||
tls?: TLSConfig,
|
||||
): Promise<LdapClient> {
|
||||
let secureContext;
|
||||
if (tls && tls.certs && tls.keys) {
|
||||
const cert = await readFile(tls.certs, 'utf-8');
|
||||
const key = await readFile(tls.keys, 'utf-8');
|
||||
secureContext = tlsLib.createSecureContext({
|
||||
cert: cert,
|
||||
key: key,
|
||||
});
|
||||
}
|
||||
|
||||
const client = ldap.createClient({
|
||||
url: target,
|
||||
tlsOptions: tls,
|
||||
tlsOptions: {
|
||||
secureContext,
|
||||
rejectUnauthorized: tls?.rejectUnauthorized,
|
||||
},
|
||||
});
|
||||
|
||||
// We want to have a catch-all error handler at the top, since the default
|
||||
|
||||
@@ -80,7 +80,11 @@ describe('readLdapConfig', () => {
|
||||
{
|
||||
target: 'target',
|
||||
bind: { dn: 'bdn', secret: 's' },
|
||||
tls: { rejectUnauthorized: false },
|
||||
tls: {
|
||||
rejectUnauthorized: false,
|
||||
keys: '/tmp/keys.pem',
|
||||
certs: '/tmp/certs.pem',
|
||||
},
|
||||
users: {
|
||||
dn: 'udn',
|
||||
options: {
|
||||
@@ -140,7 +144,11 @@ describe('readLdapConfig', () => {
|
||||
{
|
||||
target: 'target',
|
||||
bind: { dn: 'bdn', secret: 's' },
|
||||
tls: { rejectUnauthorized: false },
|
||||
tls: {
|
||||
rejectUnauthorized: false,
|
||||
keys: '/tmp/keys.pem',
|
||||
certs: '/tmp/certs.pem',
|
||||
},
|
||||
users: {
|
||||
dn: 'udn',
|
||||
options: {
|
||||
|
||||
@@ -49,6 +49,10 @@ export type LdapProviderConfig = {
|
||||
export type TLSConfig = {
|
||||
// Node TLS rejectUnauthorized
|
||||
rejectUnauthorized?: boolean;
|
||||
// A file containing private keys in PEM format
|
||||
keys?: string;
|
||||
// A file containing cert chains in PEM format
|
||||
certs?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -205,6 +209,8 @@ export function readLdapConfig(config: Config): LdapProviderConfig[] {
|
||||
}
|
||||
return {
|
||||
rejectUnauthorized: c.getOptionalBoolean('rejectUnauthorized'),
|
||||
keys: c.getOptionalString('keys'),
|
||||
certs: c.getOptionalString('certs'),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ function decode(
|
||||
function formatGUID(objectGUID: string | Buffer): string {
|
||||
let data: Buffer;
|
||||
if (typeof objectGUID === 'string') {
|
||||
data = new Buffer(objectGUID, 'binary');
|
||||
data = Buffer.from(objectGUID, 'binary');
|
||||
} else {
|
||||
data = objectGUID;
|
||||
}
|
||||
|
||||
@@ -5691,9 +5691,9 @@ __metadata:
|
||||
"@backstage/plugin-catalog-common": "workspace:^"
|
||||
"@backstage/plugin-catalog-node": "workspace:^"
|
||||
"@backstage/types": "workspace:^"
|
||||
"@types/ldapjs": ^2.2.0
|
||||
"@types/ldapjs": ^2.2.5
|
||||
"@types/lodash": ^4.14.151
|
||||
ldapjs: ^2.2.0
|
||||
ldapjs: ^2.3.3
|
||||
lodash: ^4.17.21
|
||||
uuid: ^9.0.0
|
||||
winston: ^3.2.1
|
||||
@@ -18988,7 +18988,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/ldapjs@npm:^2.2.0":
|
||||
"@types/ldapjs@npm:^2.2.5":
|
||||
version: 2.2.5
|
||||
resolution: "@types/ldapjs@npm:2.2.5"
|
||||
dependencies:
|
||||
@@ -33246,7 +33246,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ldapjs@npm:^2.2.0":
|
||||
"ldapjs@npm:^2.3.3":
|
||||
version: 2.3.3
|
||||
resolution: "ldapjs@npm:2.3.3"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user