summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Valente <82235632+hugovalente-pm@users.noreply.github.com>2024-04-10 10:00:48 +0100
committerGitHub <noreply@github.com>2024-04-10 12:00:48 +0300
commitd9c5f204588e196b90046ecd39cbd1e4cb35b69b (patch)
tree93148e25110667622a8e23204593907f020b304b
parentf4ada267cbe2311083785a59f8fe9afdbb6911ba (diff)
add Okta SSO integration (#17351)
* add Okta SSO integration * add Okta SSO integration * add new authentication integration logic to the generation script * apply Ilya's edits * Apply suggestions from code review * Update integrations/cloud-authentication/metadata.yaml * Update okta_sso.md --------- Co-authored-by: Fotis Voutsas <fotis@netdata.cloud> Co-authored-by: Ilya Mashchenko <ilya@netdata.cloud>
-rw-r--r--integrations/categories.yaml8
-rw-r--r--integrations/cloud-authentication/integrations/okta_sso.md49
-rw-r--r--integrations/cloud-authentication/metadata.yaml41
-rw-r--r--integrations/gen_docs_integrations.py69
-rwxr-xr-xintegrations/gen_integrations.py110
-rw-r--r--integrations/schemas/authentication.json71
-rw-r--r--integrations/templates/overview.md2
-rw-r--r--integrations/templates/overview/authentication.md9
8 files changed, 356 insertions, 3 deletions
diff --git a/integrations/categories.yaml b/integrations/categories.yaml
index 670244340a..cd311858b1 100644
--- a/integrations/categories.yaml
+++ b/integrations/categories.yaml
@@ -418,7 +418,7 @@
name: exporters
description: "Exporter Integrations"
most_popular: true
- priority: 5
+ priority: 6
children: []
- id: notify
name: notifications
@@ -438,3 +438,9 @@
most_popular: true
priority: 1
children: []
+- id: auth
+ name: authentication
+ description: "Authentication & Authorization"
+ most_popular: true
+ priority: 5
+ children: []
diff --git a/integrations/cloud-authentication/integrations/okta_sso.md b/integrations/cloud-authentication/integrations/okta_sso.md
new file mode 100644
index 0000000000..3f6dd15a0b
--- /dev/null
+++ b/integrations/cloud-authentication/integrations/okta_sso.md
@@ -0,0 +1,49 @@
+<!--startmeta
+custom_edit_url: "https://github.com/netdata/netdata/edit/master/integrations/cloud-authentication/integrations/okta_sso.md"
+meta_yaml: "https://github.com/netdata/netdata/edit/master/integrations/cloud-authentication/metadata.yaml"
+sidebar_label: "Okta SSO"
+learn_status: "Published"
+learn_rel_path: "Authentication"
+message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE AUTHENTICATION'S metadata.yaml FILE"
+endmeta-->
+
+# Okta SSO
+
+
+<img src="https://netdata.cloud/img/okta.png" width="150"/>
+
+
+Integrate your organization's Okta account with Netdata to better manage your team's access controls to Netdata Cloud.
+
+
+<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />
+
+## Setup
+
+### Prerequisites
+- An Okta account
+- A Netdata Cloud account
+- Access to the Space as an administrator
+- Space needs to be on Business plan or higher
+
+### Setting up Okta
+Steps needed to be done on Okta Admin Portal:
+1. Click on **Applications** tab and choose to **Browse App Catalogue**
+2. Find Netdata's preconfigured app for easy setup and click **Add Integration**
+3. Give the app the preferred **Application label**, for when it is displayed in your apps dashboard,
+and click Next to move to the Sign-On options tab
+5. In the **Sign-On Options** all the values we expect are already filled and no additional data is required
+6. Click **Done**. You are be able to go back and edit any fields later if need be
+7. Go to the **Assignments** tab and enter the People or Group assignments as per your organization’s policies
+
+### Netdata Configuration Steps
+1. Click on the Space settings cog (located above your profile icon)
+2. Click on the **Authentication** tab
+3. On the Okta SSO card, click on **Configure**
+4. Fill in the required credentials, you get them from **Okta Admin Portal**:
+ - **Issuer URL** you can get it from your profile icon on top, e.g. `https://company-name.okta.com`
+ - **Client ID** you can get it from **General** tab on application you configured on Okta
+ - **Client Secret** you can get it from **General** tab on application you configured on Okta
+ Note: [Okta - Find your application credentials](https://developer.okta.com/docs/guides/find-your-app-credentials/main/)
+
+
diff --git a/integrations/cloud-authentication/metadata.yaml b/integrations/cloud-authentication/metadata.yaml
new file mode 100644
index 0000000000..18925d5d53
--- /dev/null
+++ b/integrations/cloud-authentication/metadata.yaml
@@ -0,0 +1,41 @@
+# yamllint disable rule:line-length
+---
+- id: 'okta-authentication'
+ meta:
+ name: 'Okta SSO'
+ link: 'https://netdata.cloud'
+ categories:
+ - auth
+ icon_filename: 'okta.png'
+ keywords:
+ - sso
+ - okta
+ - okta-sso
+ overview:
+ authentication_description: "Integrate your organization's Okta account with Netdata to better manage your team's access controls to Netdata Cloud."
+ authentication_limitations: ''
+ setup:
+ description: |
+ ### Prerequisites
+ - An Okta account
+ - A Netdata Cloud account
+ - Access to the Space as an administrator
+ - Space needs to be on the Business plan or higher
+
+ ### Setting up Okta
+ Steps needed to be done on Okta Admin Portal:
+ 1. Click on **Applications** tab and choose to **Browse App Catalogue**
+ 2. Find Netdata's preconfigured app for easy setup and click **Add Integration**
+ 3. Give the app, that will be in your apps dashboard, the preferred **Application label** and click **Next** to move to the Sign-On options tab
+ 4. In the **Sign-On Options** all the values we expect are already filled and no additional data is required
+ 5. Click **Done**. You are able to go back and edit any fields later if need be
+ 6. Go to the **Assignments** tab and enter the People or Group assignments as per your organization’s policies
+
+ ### Netdata Configuration Steps
+ 1. Click on the Space settings cog (located above your profile icon)
+ 2. Click on the **Authentication** tab
+ 3. On the Okta SSO card, click on **Configure**
+ 4. Fill in the [required credentials](https://developer.okta.com/docs/guides/find-your-app-credentials/main/), you get them from **Okta Admin Portal**:
+ - **Issuer URL** you can get it from your profile icon on top, e.g. `https://company-name.okta.com`
+ - **Client ID** you can get it from **General** tab on application you configured on Okta
+ - **Client Secret** you can get it from **General** tab on application you configured on Okta
diff --git a/integrations/gen_docs_integrations.py b/integrations/gen_docs_integrations.py
index d6306e811a..27d2ce72e3 100644
--- a/integrations/gen_docs_integrations.py
+++ b/integrations/gen_docs_integrations.py
@@ -25,6 +25,9 @@ def cleanup():
for element in Path("integrations/cloud-notifications").glob('**/*/'):
if "integrations" in str(element) and not "metadata.yaml" in str(element):
shutil.rmtree(element)
+ for element in Path("integrations/cloud-authentication").glob('**/*/'):
+ if "integrations" in str(element) and not "metadata.yaml" in str(element):
+ shutil.rmtree(element)
def generate_category_from_name(category_fragment, category_array):
"""
@@ -80,6 +83,9 @@ def add_custom_edit_url(markdown_string, meta_yaml_link, sidebar_label_string, m
elif mode == 'agent-notifications':
path_to_md_file = meta_yaml_link.replace("metadata.yaml", "README")
+ elif mode == 'cloud-authentication':
+ path_to_md_file = meta_yaml_link.replace("metadata.yaml", f'integrations/{clean_string(sidebar_label_string)}')
+
output = markdown_string.replace(
"<!--startmeta",
f'<!--startmeta\ncustom_edit_url: \"{path_to_md_file}.md\"')
@@ -244,6 +250,39 @@ endmeta-->
except Exception as e:
print("Exception in notification md construction", e, integration['id'])
+
+ # AUTHENTICATIONS
+ elif mode == 'authentication':
+ if True:
+ # initiate the variables for the authentication method
+ meta_yaml = integration['edit_link'].replace("blob", "edit")
+ sidebar_label = integration['meta']['name']
+ learn_rel_path = generate_category_from_name(integration['meta']['categories'][0].split("."), categories)
+
+ # build the markdown string
+ md = \
+ f"""<!--startmeta
+meta_yaml: "{meta_yaml}"
+sidebar_label: "{sidebar_label}"
+learn_status: "Published"
+learn_rel_path: "{learn_rel_path.replace("authentication", "Authentication")}"
+message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE AUTHENTICATION'S metadata.yaml FILE"
+endmeta-->
+
+{create_overview(integration, integration['meta']['icon_filename'])}"""
+
+ if integration['setup']:
+ md += f"""
+{integration['setup']}
+"""
+
+ if integration['troubleshooting']:
+ md += f"""
+{integration['troubleshooting']}
+"""
+
+ # except Exception as e:
+ # print("Exception in authentication md construction", e, integration['id'])
if "community" in integration['meta'].keys():
community = "<img src=\"https://img.shields.io/badge/maintained%20by-Community-blue\" />"
@@ -329,6 +368,29 @@ def write_to_file(path, md, meta_yaml, sidebar_label, community, mode='default')
except FileNotFoundError as e:
print("Exception in writing to file", e)
+ elif mode == 'authentication':
+
+ name = clean_string(integration['meta']['name'])
+
+ if not Path(f'{path}/integrations').exists():
+ Path(f'{path}/integrations').mkdir()
+
+ # proper_edit_name = meta_yaml.replace(
+ # "metadata.yaml", f'integrations/{clean_string(sidebar_label)}.md\"')
+
+ md = add_custom_edit_url(md, meta_yaml, sidebar_label, mode='cloud-authentication')
+
+ finalpath = f'{path}/integrations/{name}.md'
+
+ try:
+ clean_and_write(
+ md,
+ Path(finalpath)
+ )
+
+ except FileNotFoundError as e:
+ print("Exception in writing to file", e)
+
def make_symlinks(symlink_dict):
"""
@@ -386,5 +448,12 @@ for integration in integrations:
path = build_path(meta_yaml)
write_to_file(path, md, meta_yaml, sidebar_label, community, mode='notification')
+ elif integration['integration_type'] == "authentication":
+
+ meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
+ integration, mode='authentication')
+ path = build_path(meta_yaml)
+ write_to_file(path, md, meta_yaml, sidebar_label, community, mode='authentication')
+
make_symlinks(symlink_dict)
diff --git a/integrations/gen_integrations.py b/integrations/gen_integrations.py
index 2b188b630f..c217c976db 100755
--- a/integrations/gen_integrations.py
+++ b/integrations/gen_integrations.py
@@ -45,6 +45,10 @@ NOTIFICATION_SOURCES = [
(AGENT_REPO, INTEGRATIONS_PATH / 'cloud-notifications' / 'metadata.yaml', False),
]
+AUTHENTICATION_SOURCES = [
+ (AGENT_REPO, INTEGRATIONS_PATH / 'cloud-authentication' / 'metadata.yaml', False),
+]
+
COLLECTOR_RENDER_KEYS = [
'alerts',
'metrics',
@@ -66,6 +70,12 @@ NOTIFICATION_RENDER_KEYS = [
'troubleshooting',
]
+AUTHENTICATION_RENDER_KEYS = [
+ 'overview',
+ 'setup',
+ 'troubleshooting',
+]
+
CUSTOM_TAG_PATTERN = re.compile('\\{% if .*?%\\}.*?\\{% /if %\\}|\\{%.*?%\\}', flags=re.DOTALL)
FIXUP_BLANK_PATTERN = re.compile('\\\\\\n *\\n')
@@ -117,6 +127,11 @@ NOTIFICATION_VALIDATOR = Draft7Validator(
registry=registry,
)
+AUTHENTICATION_VALIDATOR = Draft7Validator(
+ {'$ref': './authentication.json#'},
+ registry=registry,
+)
+
COLLECTOR_VALIDATOR = Draft7Validator(
{'$ref': './collector.json#'},
registry=registry,
@@ -384,6 +399,51 @@ def load_notifications():
return ret
+def _load_authentication_file(file, repo):
+ debug(f'Loading { file }.')
+ data = load_yaml(file)
+
+ if not data:
+ return []
+
+ try:
+ AUTHENTICATION_VALIDATOR.validate(data)
+ except ValidationError:
+ warn(f'Failed to validate { file } against the schema.', file)
+ return []
+
+ if 'id' in data:
+ data['integration_type'] = 'authentication'
+ data['_src_path'] = file
+ data['_repo'] = repo
+ data['_index'] = 0
+
+ return [data]
+ else:
+ ret = []
+
+ for idx, item in enumerate(data):
+ item['integration_type'] = 'authentication'
+ item['_src_path'] = file
+ item['_repo'] = repo
+ item['_index'] = idx
+ ret.append(item)
+
+ return ret
+
+
+def load_authentications():
+ ret = []
+
+ for repo, path, match in AUTHENTICATION_SOURCES:
+ if match and path.exists() and path.is_dir():
+ for file in path.glob(METADATA_PATTERN):
+ ret.extend(_load_authentication_file(file, repo))
+ elif not match and path.exists() and path.is_file():
+ ret.extend(_load_authentication_file(path, repo))
+
+ return ret
+
def make_id(meta):
if 'monitored_instance' in meta:
@@ -652,6 +712,49 @@ def render_notifications(categories, notifications, ids):
return notifications, clean_notifications, ids
+def render_authentications(categories, authentications, ids):
+ debug('Sorting authentications.')
+
+ sort_integrations(authentications)
+
+ debug('Checking authentication ids.')
+
+ authentications, ids = dedupe_integrations(authentications, ids)
+
+ clean_authentications = []
+
+ for item in authentications:
+ item['edit_link'] = make_edit_link(item)
+
+ clean_item = deepcopy(item)
+
+ for key in AUTHENTICATION_RENDER_KEYS:
+
+ if key in item.keys():
+ template = get_jinja_env().get_template(f'{ key }.md')
+ data = template.render(entry=item, clean=False)
+ clean_data = template.render(entry=item, clean=True)
+
+ if 'variables' in item['meta']:
+ template = get_jinja_env().from_string(data)
+ data = template.render(variables=item['meta']['variables'], clean=False)
+ template = get_jinja_env().from_string(clean_data)
+ clean_data = template.render(variables=item['meta']['variables'], clean=True)
+ else:
+ data = ''
+ clean_data = ''
+
+ item[key] = data
+ clean_item[key] = clean_data
+
+ for k in ['_src_path', '_repo', '_index']:
+ del item[k], clean_item[k]
+
+ clean_authentications.append(clean_item)
+
+ return authentications, clean_authentications, ids
+
+
def render_integrations(categories, integrations):
template = get_jinja_env().get_template('integrations.js')
data = template.render(
@@ -675,16 +778,19 @@ def main():
deploy = load_deploy()
exporters = load_exporters()
notifications = load_notifications()
+ authentications = load_authentications()
collectors, clean_collectors, ids = render_collectors(categories, collectors, dict())
deploy, clean_deploy, ids = render_deploy(distros, categories, deploy, ids)
exporters, clean_exporters, ids = render_exporters(categories, exporters, ids)
notifications, clean_notifications, ids = render_notifications(categories, notifications, ids)
+ authentications, clean_authentications, ids = render_authentications(categories, authentications, ids)
+
- integrations = collectors + deploy + exporters + notifications
+ integrations = collectors + deploy + exporters + notifications + authentications
render_integrations(categories, integrations)
- clean_integrations = clean_collectors + clean_deploy + clean_exporters + clean_notifications
+ clean_integrations = clean_collectors + clean_deploy + clean_exporters + clean_notifications + clean_authentications
render_json(categories, clean_integrations)
diff --git a/integrations/schemas/authentication.json b/integrations/schemas/authentication.json
new file mode 100644
index 0000000000..bf302837a2
--- /dev/null
+++ b/integrations/schemas/authentication.json
@@ -0,0 +1,71 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Netdata authentication mechanism metadata.",
+ "oneOf": [
+ {
+ "$ref": "#/$defs/entry"
+ },
+ {
+ "type": "array",
+ "minLength": 1,
+ "items": {
+ "$ref": "#/$defs/entry"
+ }
+ }
+ ],
+ "$defs": {
+ "entry": {
+ "type": "object",
+ "description": "Data for a single authentication method.",
+ "properties": {
+ "id": {
+ "$ref": "./shared.json#/$defs/id"
+ },
+ "meta": {
+ "$ref": "./shared.json#/$defs/instance"
+ },
+ "keywords": {
+ "$ref": "./shared.json#/$defs/keywords"
+ },
+ "overview": {
+ "type": "object",
+ "description": "General information about the authentication method.",
+ "properties": {
+ "authentication_description": {
+ "type": "string",
+ "description": "General description of what the authentication method does."
+ },
+ "authentication_limitations": {
+ "type": "string",
+ "description": "Explanation of any limitations of the authentication method."
+ }
+ },
+ "required": [
+ "authentication_description",
+ "authentication_limitations"
+ ]
+ },
+ "setup": {
+ "oneOf": [
+ {
+ "$ref": "./shared.json#/$defs/short_setup"
+ },
+ {
+ "$ref": "./shared.json#/$defs/full_setup"
+ }
+ ]
+ },
+ "troubleshooting": {
+ "$ref": "./shared.json#/$defs/troubleshooting"
+ }
+ },
+ "required": [
+ "id",
+ "meta",
+ "keywords",
+ "overview",
+ "setup"
+ ]
+ }
+ }
+}
diff --git a/integrations/templates/overview.md b/integrations/templates/overview.md
index b89e515439..3063b68606 100644
--- a/integrations/templates/overview.md
+++ b/integrations/templates/overview.md
@@ -4,4 +4,6 @@
[% include 'overview/exporter.md' %]
[% elif entry.integration_type == 'notification' %]
[% include 'overview/notification.md' %]
+[% elif entry.integration_type == 'authentication' %]
+[% include 'overview/authentication.md' %]
[% endif %]
diff --git a/integrations/templates/overview/authentication.md b/integrations/templates/overview/authentication.md
new file mode 100644
index 0000000000..f7fa77520f
--- /dev/null
+++ b/integrations/templates/overview/authentication.md
@@ -0,0 +1,9 @@
+# [[ entry.meta.name ]]
+
+[[ entry.overview.authentication_description ]]
+[% if entry.overview.authentication_limitations %]
+
+## Limitations
+
+[[ entry.overview.authentication_limitations ]]
+[% endif %]