From cad438f99c80af22877a993a02bbd1b14848046c Mon Sep 17 00:00:00 2001 From: mortenlj Date: Tue, 17 Sep 2024 09:12:27 +0000 Subject: [PATCH] Build: (3dcb456) Document how to enable Aiven for a tenant --- 404.html | 23 + administrative/fixtures/index.html | 27 +- administrative/slack/index.html | 27 +- index.html | 27 +- search/search_index.json | 2 +- sitemap.xml | 5 + sitemap.xml.gz | Bin 434 -> 440 bytes social/the-great-outdoors/index.html | 27 +- technical/doc-guidelines/index.html | 27 +- technical/external-ingress/index.html | 27 +- technical/narcos/index.html | 27 +- technical/narcos/reference/cluster/index.html | 27 +- technical/narcos/reference/tenant/index.html | 27 +- technical/observability/index.html | 27 +- technical/overview/index.html | 27 +- technical/production-ready/index.html | 27 +- technical/publications-media/index.html | 27 +- .../tenant-setup/addons/aiven/index.html | 1490 +++++++++++++++++ .../tenant-setup/addons/azure-ad/index.html | 33 +- .../tenant-setup/addons/digdir/index.html | 27 +- .../tenant-setup/addons/tokenx/index.html | 27 +- .../tenant-setup/addons/wonderwall/index.html | 29 +- technical/tenant-setup/index.html | 33 +- technical/upgrading-kafka/index.html | 27 +- welcome/nais-manifest-eng/index.html | 27 +- welcome/nais-sponsor/index.html | 27 +- 26 files changed, 2051 insertions(+), 50 deletions(-) create mode 100644 technical/tenant-setup/addons/aiven/index.html diff --git a/404.html b/404.html index e519fc72..e31a0a6f 100644 --- a/404.html +++ b/404.html @@ -808,6 +808,8 @@ + + @@ -844,6 +846,27 @@ +
  • + + + + + Aiven services and Kafka + + + + +
  • + + + + + + + + + +
  • diff --git a/administrative/fixtures/index.html b/administrative/fixtures/index.html index ef5c11e9..c43f02f3 100644 --- a/administrative/fixtures/index.html +++ b/administrative/fixtures/index.html @@ -879,6 +879,8 @@ + + @@ -915,6 +917,27 @@ +
  • + + + + + Aiven services and Kafka + + + + +
  • + + + + + + + + + +
  • @@ -1208,7 +1231,7 @@

    Weekly - 2024-09-17 + 2024-09-17 @@ -1218,7 +1241,7 @@

    Weekly - 2024-09-17 + 2024-09-17 diff --git a/administrative/slack/index.html b/administrative/slack/index.html index a4a22950..6473dc72 100644 --- a/administrative/slack/index.html +++ b/administrative/slack/index.html @@ -888,6 +888,8 @@ + + @@ -924,6 +926,27 @@ +
  • + + + + + Aiven services and Kafka + + + + +
  • + + + + + + + + + +
  • @@ -1223,7 +1246,7 @@

    Public Channels - 2024-09-17 + 2024-09-17 @@ -1233,7 +1256,7 @@

    Public Channels - 2024-09-17 + 2024-09-17 diff --git a/index.html b/index.html index 0ddc86ed..556b6872 100644 --- a/index.html +++ b/index.html @@ -827,6 +827,8 @@ + + @@ -863,6 +865,27 @@ +
  • + + + + + Aiven services and Kafka + + + + +
  • + + + + + + + + + +
  • @@ -1130,7 +1153,7 @@

    A handbook of sorts - 2024-09-17 + 2024-09-17 @@ -1140,7 +1163,7 @@

    A handbook of sorts - 2024-09-17 + 2024-09-17 diff --git a/search/search_index.json b/search/search_index.json index e7feafe4..99951558 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"A handbook of sorts","text":"

    Here we will cover the parts \"unique\" to us and therefore weren't covered during onboarding

    Nais is a complex animal - and if you are new to the team there will be quite a few things that are all but obvious and apparent.

    Factoids about the team are posted on Slack. Take a minute to present your facts, and find out about your colleagues.

    The technical documentation is comprehensive but hardly describes how we function as a team. This handbook is an attempt at bringing some of the silent knowledge to an audible frequency, and at the very least guide you through the bare essentials. To get you started we recommend that you familiarize yourself with our manifest. The guiding principles that define the how, the what, and the why we do the things that we do.

    So now that have you have memorized the manifest and documentation we can get into it all.

    "},{"location":"administrative/fixtures/","title":"Fixtures","text":"

    The NAIS team might look disorganised to a newcomer and in a certain sense of the word this holds true. However there are a few fixtures in place to ensure a certain degree of synchronisation, consensus and progression.

    "},{"location":"administrative/fixtures/#froom","title":"Froom","text":"

    Thanks to COVID19 we have become \"remote first only\". And in case you are wondering; The froom is our zoom based digital workspace. Froom is a portmanteau of Frode and Zoom. Frode is a popular guy, so his personal Zoom space was where we all gravitated.

    We all hang out in the lobby and join breakout rooms for more in-depth exploration of topics that may not be of general interest. Anyone is welcome anywhere but \"good manners\" apply. Make your presence known when joining and if you sense that you will be interupting trains of thought or coding flow, come back later or use Slack instead. The froom url is posted in the topic here.

    All meeting fixtures are held in The froom as well as ad-hoc and sceduled meetings with third parties.

    Any and all meetings that are deemed unnecessary due to priority or lack of substance are swiftly cancelled and we all go back to [insert task].

    "},{"location":"administrative/fixtures/#weekly","title":"Weekly","text":"

    The NAIS weekly takes place Monday at high noon.

    "},{"location":"administrative/slack/","title":"Slack","text":""},{"location":"administrative/slack/#we-do-not-want-to-leave-anyone-out-but-invites-and-inclusion-can-sometimes-fall-between-the-cracks","title":"We do not want to leave anyone out but invites and inclusion can sometimes fall between the cracks.","text":"

    Here is a list of Slack channels you might want to join (or in some cases should be in). If you haven't been invited to a private channel listed here let your sponsor know.

    "},{"location":"administrative/slack/#private-channels","title":"Private Channels","text":"

    #nais-internal #nais-tech

    "},{"location":"administrative/slack/#public-channels","title":"Public Channels","text":"

    #nais

    #naisdevice

    #nais-announcements

    "},{"location":"social/the-great-outdoors/","title":"The Great Outdoors","text":""},{"location":"social/the-great-outdoors/#all-work-and-no-play-makes-nais-a-dull-platform","title":"\"All work and no play makes NAIS a dull platform\"","text":""},{"location":"social/the-great-outdoors/#native-naisians","title":"Native NAISians","text":""},{"location":"social/the-great-outdoors/#the-nais-pole","title":"The NAIS Pole","text":""},{"location":"technical/doc-guidelines/","title":"NAIS documentation guidelines","text":"

    When writing the documentation we serve at doc.nais.io / doc.<tenant>.cloud.nais.io, we want to make sure that the content we provide helps our users to understand and use the platform we're making.

    Some key points to keep in mind when writing the docs are:

    • Following the diataxis theory
    • Less is more: Keep it short and to the point. This makes it easier to sustain high quality over time.
    • We are writing docs for the users of our platform. No one else. We should be empathetic to their needs and understanding of the platform, and be mindful of adding details that are not relevant in the current documentation context
    • Consistency in style and tone
    • NAIS Quality
    "},{"location":"technical/doc-guidelines/#structure","title":"Structure","text":"

    We structure our content primarily around what services NAIS provide, with some honest exceptions.

    Under each service, or category of services, we use Diataxis with the following convention:

    The main page for a service is an Explanation of the service. It should give a high-level overview of what the service is, why you would use it, and how it fits into the NAIS ecosystem.

    Example structure:

    some-service/\n\u251c\u2500 README.md # <- explanation\n\u251c\u2500 how-to/\n\u2502  \u251c\u2500 verb.md\n\u251c\u2500 reference/\n\u2502  \u251c\u2500 spec.md\n\u251c\u2500 .pages\n
    Collapsed reference structure

    If the service contains a single reference page, name the page README.md. This will collapse the directory structure in the navigation menu.

    "},{"location":"technical/doc-guidelines/#honest-exceptions","title":"Honest exceptions","text":"
    • Top-level explanations
    • Top-level tutorials
    • Operate: Here we describe the tools and services that are used and required to operate the platform
    • Tags overview
    • Legal stuff
    "},{"location":"technical/doc-guidelines/#pages-file","title":".pages file","text":"

    The .pages file is used to define overrides and customizations to the titles and order of the pages in the navigation menu. This is a feature of the Awesome Pages plugin for MkDocs.

    A conventional .pages file looks like this:

    .pages
    title: My overridden title\nnav:\n- README.md\n- \ud83d\udca1 Explanations: explanations\n- \ud83c\udfaf How-To: how-to\n- \ud83d\udcda Reference: reference\n- application\n- job\n- ...\n
    "},{"location":"technical/doc-guidelines/#conventions","title":"Conventions","text":""},{"location":"technical/doc-guidelines/#documentation-structure","title":"Documentation structure","text":"

    The file tree represents the structure of the navigation menu. The H1 (#) will be the title of the page and the title in the navigation menu

    To override the placement in the navigation menu, we use the Awesome Pages plugin for MkDocs.

    "},{"location":"technical/doc-guidelines/#placeholder-variables","title":"Placeholder variables","text":"

    Where the reader is expected to change the content, we use placeholder variables. These variables are written in uppercase, with words separated by hyphens, surrounded by <>. For example: <MY-APP>.

    "},{"location":"technical/doc-guidelines/#tenant-variables","title":"Tenant variables","text":"

    We template the tenant name in the documentation using <<tenant()>> When the documentation is built, this will be replaced with the relevant tenant name.

    For even more convenience, we have a <<tenant_url(\"service\")>> function that will replace the service with the relevant URL for the service and create a full tenant URL to the service. An optional second parameter can be used to specify the path to the service eg. <<tenant_url(\"grafana\", \"explore\")>>

    "},{"location":"technical/doc-guidelines/#tenant-specific-content","title":"Tenant-specific content","text":"

    Some sections are specific for a given tenant:

    page.md
    {%- if tenant() == \"nav\" %}\nTenant-specific content\n{%- endif %}\n

    ...or for multiple tenants:

    page.md
    {%- if tenant() in (\"nav\", \"dev-nais\") %}\nTenant-specific content\n{%- endif %}\n
    "},{"location":"technical/doc-guidelines/#tenant-specific-pages","title":"Tenant-specific pages","text":"

    If an entire page is specific to a tenant, specify the conditional field in the markdown front matter:

    page.md
    ---\nconditional: [tenant, <tenant-name>]\n---\n\n# Title\n\n...\n
    • tenant marks the page as tenant-specific.
    • <tenant-name> specifies which tenant that the page should be shown for.
    "},{"location":"technical/doc-guidelines/#code-blocks","title":"Code blocks","text":"

    When using code blocks, set the correct language for syntax highlighting. Define a title and highlight lines if needed.

    page.md
    ```yaml title=\"describe content / filename\" hl_lines=\"6-8 11\"\napiVersion: nais.io/v1alpha1\nkind: Application\n...\n```\n
    "},{"location":"technical/doc-guidelines/#alternate-paths","title":"Alternate paths","text":"

    When the user is given a choice, we want to show both paths in the documentation. For example programming language, OS or different methods

    page.md
    === \"Linux\"\n\n  linux specific stuff\n\n=== \"macOS\"\n\n  macOS specific stuff\n

    Indentation and blank lines

    Ensure you have tab indentation on the content block, as well as a blank line before and after.

    "},{"location":"technical/doc-guidelines/#links","title":"Links","text":"

    We want to make sure that the links are consistent and easy to understand. We use the following structure for links:

    Type of Link Icon Link Explanation [:bulb: Learn more about ...](../) How-to guide [:dart: Learn how to ...](../) Reference [:books: Reference for ](../) Tutorial [:rocket: Tutorial for ...](../) External link [:octicons-link-external-24: External link](https://...) Prometheus [:simple-prometheus: Open Prometheus](../) Grafana [:simple-grafana: Open Grafana](../)"},{"location":"technical/doc-guidelines/#gcp-only-features","title":"GCP only features","text":"

    Features that are only available in GCP clusters should preferably be marked in a consistent way.

    For that purpose, a macro is available to add a warning in the text:

    page.md
    # Aiven Redis\n\n<<gcp_only(\"Aiven Redis\")>>\n\nAiven Redis is ...\n
    "},{"location":"technical/doc-guidelines/#tags","title":"Tags","text":"

    We use tags to categorize and group the content to make it easier to find, as an alternative to the navigation menu and search.

    Tags are written in the front matter of the markdown file like so:

    page.md
    ---\ntags: [tag1, tag2]\n---\n\n# Title\n\n...\n
    "},{"location":"technical/doc-guidelines/#which-tags-should-i-use","title":"Which tags should I use?","text":"

    Tags should group multiple related pages together. Avoid using tags that only apply to a single page. This helps keeping the Tags-overview page cleaner.

    We typically always tag the diataxis-type the page classifies as with these mappings:

    Form Tag Explanation explanation How-to guide how-to Reference reference Tutorial tutorial

    Tag each page with the parent category or service that it belongs to.

    For example, these would be the tags for metrics and tracing in the observability category:

    observability/\n\u251c\u2500 README.md           # tags: [observability, explanation]\n\u251c\u2500 metrics/\n\u2502  \u251c\u2500 README.md        # tags: [observability, metrics, explanation]\n\u2502  \u251c\u2500 how-to/\n|  |  \u251c\u2500 how-to1.md    # tags: [metrics, how-to]\n|  \u251c\u2500 reference/\n\u2502  |  \u251c\u2500 spec.md       # tags: [metrics, reference]\n\u251c\u2500 tracing/\n\u2502  \u251c\u2500 README.md        # tags: [observability, tracing, explanation]\n\u2502  \u251c\u2500 how-to/\n|  |  \u251c\u2500 how-to1.md    # tags: [tracing, how-to]\n|  \u251c\u2500 reference/\n\u2502  |  \u251c\u2500 spec.md       # tags: [tracing, reference]\n
    "},{"location":"technical/doc-guidelines/#diataxis-httpsdiataxisfr","title":"Diataxis (https://diataxis.fr/)","text":"

    Di\u00e1taxis identifies four distinct needs, and four corresponding forms of documentation - tutorials, how-to guides, technical reference and explanation. It places them in a systematic relationship, and proposes that documentation should itself be organised around the structures of those needs.

    To create contents you must determine what you are setting out to do. Are you writing a Tutorial, a How-to guide, a Reference or is it a comprehensive Explanantion of a concept.

    "},{"location":"technical/doc-guidelines/#tutorial","title":"Tutorial","text":"

    A tutorial is an experience that takes place under the guidance of a tutor. A tutorial is always learning-oriented.

    "},{"location":"technical/doc-guidelines/#how-to","title":"How-to","text":"

    How-to guides are directions that guide the reader through a problem or towards a result. How-to guides are goal-oriented.

    "},{"location":"technical/doc-guidelines/#reference","title":"Reference","text":"

    Reference guides are technical descriptions of the machinery and how to operate it. Reference material is information-oriented.

    "},{"location":"technical/doc-guidelines/#explanation","title":"Explanation","text":"

    Explanation is a discusive treatment of a subject, that permits reflection. Explanation is understanding-oriented.

    "},{"location":"technical/external-ingress/","title":"External ingress","text":"

    We support adding external ingresses that other controls using cert-manager. This is easily done by adding a CNAME record pointing to an ingress we control.

    Read more about delegated domains for dns01 at cert-manager.io/docs.

    Underneath I've written the steps needed to take for us to get this working.

    "},{"location":"technical/external-ingress/#getting-external-ingress-up-and-running","title":"Getting external ingress up and running","text":"

    I'm going to use detsombetyrnoe.no as an example.

    1. Ask the secops team do add the following to the domain

      _acme-challenge.detsombetyrnoe.no  IN  CNAME  _acme-challenge.detsombetyrnoe.inter.nav.no.\n
    2. Create an Kubernetes Issuer:

      apiVersion: cert-manager.io/v1\nkind: Issuer\nmetadata:\n  name: detsombetyrnoe-no\n  namespace: nais-system\nspec:\n  acme:\n    email: frode.sundby@nav.no\n    preferredChain: ISRG Root X1\n    privateKeySecretRef:\n      name: cloud-nais-io-account-key\n    server: https://acme-v02.api.letsencrypt.org/directory\n    solvers:\n    - selector:\n        dnsZones:\n          - detsombetyrnoe.no\n      dns01:\n        cnameStrategy: Follow\n        cloudDNS:\n          hostedZoneName: intern-nav-no\n          project: nais-prod-020f\n

      You can use dnsName if you don't have subdomains, or if you want to be explicit.

    3. Then create a Kubernetes Certificate:

      apiVersion: cert-manager.io/v1\nkind: Certificate\nmetadata:\n  name: wc-detsombetyrnoe-no\n  namespace: nais-system\nspec:\n  dnsNames:\n  - detsombetyrnoe.no\n  - '*.detsombetyrnoe.no'\n  issuerRef:\n    name: detsombetyrnoe-no\n  secretName: wc-detsombetyrnoe-no-tls\n
    4. After the certificate has been approved by Let's encrypt, you need to notify loadbalancer about your certificate secret wc-detsombetyrnoe-no-tls. Go to Fasit > Your env > loadbalancer, and add your secret name to the Certificates list.

    5. Then you need to inform Naiserator about the new ingress, detsombetyrnoe.no. Go to Fasit > Your env > Naiserator, and add your secret name to the Extra external hosts list.
    6. Ask the user to add their new ingress to their nais.yaml.
    7. Success?
    "},{"location":"technical/external-ingress/#subdomains-yeah-but-manually","title":"Subdomains? Yeah, but manually...","text":"

    This solution also supports subdomains, but we need the secops team to add each subdomain as an _acme_challenge.

    _acme-challenge.www.detsombetyrnoe.no\tIN\tCNAME\t_acme-challenge.detsombetyrnoe.intern.nav.no.\n

    PS: Make sure there are not other issuer with the tag: issuewild!

    "},{"location":"technical/observability/","title":"Observability Stack","text":"

    This document describes the technical observability stack for nais-system Features.

    "},{"location":"technical/observability/#overview","title":"Overview","text":"

    The observability stack in nais consists of the following components:

    • Alertmanager
    • Grafana
    • Grafana Agent
    • Logging Operator
    • Loki
    • OpenTelemery Operator
    • OpenTelemetry Collector
    • Prometheus Operator
    • Prometheus
    • Tempo
    "},{"location":"technical/observability/#opentelemetry-collector","title":"OpenTelemetry Collector","text":"

    The OpenTelemetry Collector is a vendor-agnostic, open-source telemetry collector that can be used to collect, process, and export telemetry data. It is a powerful tool that can be used to collect logs, metrics, and traces from a variety of sources and export them to a variety of destinations.

    OpenTelemetry Collector implements the OpenTelemetry protocol (OTLP) which is a standard for transmitting telemetry data.

    Full otlpTraces only
    graph LR\n  Feature[Feature]\n  OtelCollector[Collector]\n  Loki\n  Prometheus\n  Tempo\n\n  Feature -- otlp --> OtelCollector\n\n  OtelCollector -- traces --> Tempo\n  OtelCollector -- logs --> Loki\n  OtelCollector -- metrics --> Prometheus\n\n  Tempo -- query --> Grafana\n  Loki -- query --> Grafana\n  Prometheus -- query --> Grafana
    graph LR\n  Feature[Feature]\n  OtelCollector[Collector]\n  LoggingOperator\n  Loki\n  Prometheus\n  Tempo\n\n  Feature -- traces --> OtelCollector\n  Feature -- stdout/stderr --> LoggingOperator\n  LoggingOperator -- forward --> Loki\n  Feature -- scrape --> Prometheus\n  OtelCollector -- traces --> Tempo\n\n  Tempo -- query --> Grafana\n  Loki -- query --> Grafana\n  Prometheus -- query --> Grafana
    "},{"location":"technical/observability/#endpoints","title":"Endpoints","text":"

    The OpenTelemetry Collector exposes the following endpoints:

    Endpoint Description http://opentelemetry-management-collector:4317 Internal endpoint for features in nais-system namespace. https://collector-internet.<tenant>.cloud.nais.io Internet exposed endpoint for things running outside of nais.

    Fasit features can use environment values in Feature.yaml to get the correct OpenTelemetry config without hardcoding the endpoint.

    Feature.yaml
    values:\n  observability.otelp.endpoint:\n    computed:\n      template: \"{{ .Env.otel_otlp_endpoint }}\"\n  observability.otelp.protocol:\n    computed:\n      template: \"{{ .Env.otel_otlp_protocol }}\"\n  observability.otelp.insecure:\n    computed:\n      template: \"{{ .Env.otel_otlp_insecure }}\"\n
    "},{"location":"technical/observability/#tenant-clusters","title":"Tenant Clusters","text":"

    All nais clusters have a dedicated OpenTelemetry Collector instance running in the nais-system. Tenant clusters forwards to management cluster using the otlp-http endpoint so that all telemetry data from nais-system is collected in a single place.

    ---\nconfig:\n    flowchart:\n        defaultRenderer: elk\n---\n%%{init: {'theme':'dark'}}%%\nflowchart\n  subgraph \"management\"[Management Cluster]\n    subgraph \"management-nais-system\"[nais-system]\n      OtelCollector[Management Collector]\n      Tempo\n      Loki\n      Prometheus\n      Feature[Feature]\n    end\n  end\n\n  subgraph \"dev\"[Tenant Dev Cluster]\n    subgraph \"dev-nais-system\"[nais-system]\n      DevFeature[Feature]\n      DevOtelC[Management Collector]\n    end\n  end\n\n  subgraph \"prod\"[Tenant Prod Cluster]\n    subgraph \"prod-nais-system\"[nais-system]\n      ProdFeature[Feature]\n      ProdOtelC[Management Collector]\n    end\n  end\n\n  Feature -- otlp-grpc --> OtelCollector\n\n  DevFeature -- otlp-grpc --> DevOtelC\n  ProdFeature -- otlp-grpc --> ProdOtelC\n  DevOtelC -- otlp-http --> OtelCollector\n  ProdOtelC -- otlp-http --> OtelCollector\n\n  OtelCollector -- traces --> Tempo\n  OtelCollector -- logs --> Loki\n  OtelCollector -- metrics --> Prometheus
    "},{"location":"technical/overview/","title":"NAIS Overview","text":"

    This document is a high-level overview of the NAIS platform

    "},{"location":"technical/overview/#namespaces","title":"Namespaces","text":"

    Over the years we have a number of namespaces that we use for different purposes. The ones to know about are:

    Name Description nais-system Where we deliver NAIS functionality nais Team namespace for NAIS. Custom functionality for NAV nais-verification Test applications for verifying NAIS with alerts kyverno Only Kyverno is allowed in here cnrm-system Where Cloud Native Resource Manager runs. Managed by Google"},{"location":"technical/overview/#tenants","title":"Tenants","text":""},{"location":"technical/overview/#clusters","title":"Clusters","text":""},{"location":"technical/overview/#management","title":"Management","text":""},{"location":"technical/production-ready/","title":"What is production ready?","text":"

    This is the NAIS team's attempt to define what production ready means to us. Production implies quality and durability. Running a system means serving requests, and requests are ultimately serving users. We care about our users, thus we must care about our systems.

    At NAIS, we strive to:

    • provide fully self serviced products with minimal downtime,
    • be confident that code changes will not break existing functionality,
    • respond quickly when systems fail,
    • spend minimal time fixing errors,
    • and most importantly: spend as much time possible implementing useful services for our users. (you!)

    We believe that if our systems conform to the principles in this document, we have a greater chance of achieving these goals.

    "},{"location":"technical/production-ready/#12-factor-app","title":"12 factor app","text":"

    Write your application according to the principles of 12 factor apps.

    Twelve factor apps:

    • have declarative system requirements,
    • are suitable for deployment in Docker containers,
    • do not have differences between development and production, and
    • can scale up without significant changes to tooling, architecture, or development practices.
    "},{"location":"technical/production-ready/#observability","title":"Observability","text":"

    Expose a Prometheus metric endpoint to allow scraping of key application metrics.

    "},{"location":"technical/production-ready/#measuring-success","title":"Measuring success","text":"

    Figure out service level indicators (SLI) and service level objectives (SLO).

    Service level indicators are quantifying metrics such as error rate, request latency, availability, and system throughput.

    Service level objectives are targets values for your metrics. You might say that you want an uptime of 99.9%. How do you define uptime? Is it a sufficiently low error rate? Is it being able to serve requests within a reasonable amount of time?

    Implement SLIs in the application code. Create views in a Grafana dashboard to check up on SLOs.

    Recommended read: Service Level Objectives in the Google Site Reliability Engineering handbook.

    "},{"location":"technical/production-ready/#alerts","title":"Alerts","text":"

    Alerts should be tied to SLOs. Consider if alerting is at all needed. An alert should only fire if human intervention is required. Too many alerts going off will result in alarm fatigue.

    "},{"location":"technical/production-ready/#relevant-logs","title":"Relevant logs","text":"

    Ensure traceability of errors by logging sufficient amount of debug information. Do not include sensitive data in logs. Sensitive data include credentials and personally identifyable information.

    "},{"location":"technical/production-ready/#tests","title":"Tests","text":"

    Ensure sufficient test coverage so that the next developer is not afraid of breaking things when updating your code.

    "},{"location":"technical/production-ready/#documentation","title":"Documentation","text":"
    • Development/building
    • End-user documentation
    • Sysadmin/maintenance
    • Document code where it is complex, hard to read, or otherwise obscure
    "},{"location":"technical/production-ready/#continuous-integration","title":"Continuous Integration","text":"

    Ensure that changes to the codebase are built automatically, and pushed to development and production environments. No manual steps other than git push should be neccessary.

    "},{"location":"technical/production-ready/#publish-and-announce","title":"Publish and announce","text":"

    Your system is not in production until it has users. Make sure all potential end users are aware of your system and can use it. Using a system means making requests and having access to support and documentation.

    "},{"location":"technical/production-ready/#decrease-bus-factor","title":"Decrease bus factor","text":"

    Ensure that at least two people on your team have sufficient knowledge to debug and work on the system, to avoid bus factor.

    "},{"location":"technical/production-ready/#data-protection-impact-assessment","title":"Data Protection Impact Assessment","text":"

    Perform, if applicable, a Data Protection Impact Assessment (or in Norwegian, personvernskonsekvensvurdering (PVK)).

    "},{"location":"technical/production-ready/#security-audit","title":"Security Audit","text":"

    Perform a security audit (ROS) before releasing to production.

    "},{"location":"technical/publications-media/","title":"Publications & Media","text":""},{"location":"technical/publications-media/#seasoned-adventurers-giving-back","title":"Seasoned adventurers - giving back","text":"

    Our work is in large part driven by and on open source solutions and thanks to the sharing of others we enjoy a faster pace and more robust infrastructure than one might otherwise expect. With that in mind, we do try to contribute with content that describe topics and experiences that have been or are of significance. Being a public service we also try to share through talks, conferences and interactions with other government bodies and the developer community in general. Here is a collection of the past & present.

    "},{"location":"technical/publications-media/#write-ups","title":"Write ups","text":"

    NAIS blog

    "},{"location":"technical/publications-media/#presentations","title":"Presentations","text":"
    • Using Kubernetes to Change Legacy Systems and Processes in the Public Sector

    • Experiences From Running Istio in a K8s Production Environment

    • NAIS applikasjonsplattform

    • Continious Monitoring

    • Hva kjennetegner en moderne applikasjonsplattform?

    "},{"location":"technical/upgrading-kafka/","title":"Procedure to follow when upgrading Kafka","text":"

    Kafka is an important service in NAV, and problems that affect Kafka affects many teams. For that reason we have decided to describe the procedure for upgrading Kafka in detail, to have a playlist to refer to.

    The upgrade should be properly announced in #nais-announcements, with a copy to relevant channels, either by link or by copied text. For NAV, #kafka is a relevant channel. For any other tenants that use Kafka, the tenant will typically have one support channel which should get a copy of the announcement.

    "},{"location":"technical/upgrading-kafka/#1-upgrade-in-dev-nais-dev-first","title":"1. Upgrade in dev-nais-dev first","text":"

    The dev-nais tenant is our testing tenant, and allows testing platform changes without affecting developer teams. By upgrading in dev-nais-dev first, we can check that kafka-canary continues to work, and optionally run additional tests to verify that everything works.

    It is considered enough to check that the kafka-canary continues to work and handles the upgrade process without major issues.

    Once everything is confirmed to work in dev-nais-dev, rolling out to ci-nais should be next.

    Upgrading is done by changing kafka_version in the naas.tf file for dev-nais tenant, dev environment.

    "},{"location":"technical/upgrading-kafka/#2-upgrade-the-ci-nais-tenant","title":"2. Upgrade the ci-nais tenant","text":"

    The ci-nais tenant is our CI tenant, and should emulate a production tenant as close as possible. Upgrading in ci-nais will allow us to check that the upgrade process works in a tenant that is more similar to production.

    Once everything is confirmed to work in ci-nais, rolling out to other tenants/clusters should be started as soon as possible.

    Upgrading is done by changing kafka_version in the naas.tf file for ci-nais tenant, ci environment.

    "},{"location":"technical/upgrading-kafka/#3-upgrade-development-environments","title":"3. Upgrade development environments","text":"

    Currently, NAV is the only tenant that uses Kafka, but we have one project that fall in this category:

    • nav-dev

    The upgrade should be announced clearly, with a request for teams to check their applications during the upgrade and after.

    Before starting the upgrade, it is recommended to silence some alerts that typically get triggered during the upgrade:

    • HighDiskReads
    • NetworkSentInbalanced
    • HighDiskUsagePredicted

    After the upgrade, teams will have 1 week to report any issues to the nais-team, who can decide if the upgrade in production should be held back or go ahead.

    Upgrading is done by changing/adding kafka_version in the naas.tf file for nav tenant, dev-gcp environment.

    "},{"location":"technical/upgrading-kafka/#4-upgrade-remaining-environments","title":"4. Upgrade remaining environments","text":"

    When announcing the upgrade, request that teams that haven't checked their dev environment do so now, and allow for a few hours before starting the upgrade. Make sure to dedicate time to watch the upgrade progress, and follow up on any reports of problems.

    Before starting the upgrade, it is recommended to silence some alerts that typically get triggered during the upgrade:

    • HighDiskReads
    • NetworkSentInbalanced
    • HighDiskUsagePredicted
    • HighDiskWrites
    • TODO: Find links for alerts in nav-infrastructure

    Make sure to inform the users when the upgrade has completed.

    Upgrading is done by changing the default value for the kafka_version variable in these files (and remove any tenant/environment specific values):

    • modules/aiven/variables.tf
    • modules/legacy/variables.tf
    • modules/tenant/variables.tf
    "},{"location":"technical/narcos/","title":"Narcos","text":"

    NAIS Adminstrator CLI Og Scripts

    "},{"location":"technical/narcos/#installation","title":"Installation","text":"

    brew install narco

    "},{"location":"technical/narcos/#usage","title":"Usage","text":"

    See available subcommands under the Reference section in the navigation sidebar.

    "},{"location":"technical/narcos/reference/cluster/","title":"cluster command","text":"

    The cluster command let you generate kubeconfig, and list clusters available for you.

    "},{"location":"technical/narcos/reference/cluster/#kubeconfig","title":"kubeconfig","text":"

    Create a kubeconfig file for connecting to available clusters for you. This requires that you have the gcloud command line tool installed, configured and logged in. You can log in with gcloud auth login --update-adc.

    narc kubeconfig\n
    Flag Short Description overwrite Overwrite config already in the kubeconfig-file clean Delete config before retrieving new one verbose -v More output, mostly useful combined with overwrite"},{"location":"technical/narcos/reference/cluster/#list","title":"list","text":"

    List clusters available.

    narc cluster list\n
    "},{"location":"technical/narcos/reference/tenant/","title":"tenant command","text":"

    The tenant command let you list, get, and set tenant for your Naisdevice.

    "},{"location":"technical/narcos/reference/tenant/#list","title":"list","text":"

    List tenants available.

    narc tenant list\n
    "},{"location":"technical/narcos/reference/tenant/#get","title":"get","text":"

    Get your current tenant.

    narc tenant get\n
    "},{"location":"technical/narcos/reference/tenant/#set","title":"set","text":"

    Switches your tenant to the one specified. May require that you log in.

    narc tenant set TENANT\n
    "},{"location":"technical/tenant-setup/","title":"Setting up a tenant organization","text":"

    This guide is used when setting up a new tenant. This is typically done by the NAIS team, together with the tenants administrators.

    graph TD\nA[Google Tenant] --> B[NAIS Folder]\nB --> C[management]\nB --> D[dev]\nB --> E[prod]
    "},{"location":"technical/tenant-setup/#prereq","title":"Prereq","text":"
    • Google Cloud Tenant admin
    • GitHub Organization
    "},{"location":"technical/tenant-setup/#required-settings","title":"Required settings","text":""},{"location":"technical/tenant-setup/#required-permissions","title":"Required permissions","text":"

    On the user that will run the following commands, the following IAM roles are required on an organization level.

    • Owner
    • Organization Administrator
    • Folder Creator
    • Organization Policy Administrator
    "},{"location":"technical/tenant-setup/#create-the-nais-folder","title":"Create the NAIS folder","text":"

    Everything related to NAIS is contained within this folder.

    export NAAS_ORG_NAME=my-org # (1)\nexport NAAS_ORG_ID=$(gcloud organizations list --filter $NAAS_ORG_NAME | tail -n1 | awk '{print $2}')\n\ngcloud resource-manager folders create --display-name=nais --organization=$NAAS_ORG_ID\nexport NAAS_GOOGLE_FOLDERID=$(gcloud resource-manager folders list --organization=$NAAS_ORG_ID | grep nais | awk '{print $3}')\n
    1. Change this to the name of your Google Organization
    "},{"location":"technical/tenant-setup/#grant-access-to-the-nais-team-and-the-terraform-user","title":"Grant access to the NAIS team and the terraform user","text":"

    To allow the NAIS team the required permissions to operate nais, IAM policies must be added to the NAIS folder.

    Bug

    Find correct roles for the following users:

    • nais-viewers
    • nais-admins
    Copy and run this command
    cat <<EOF > naas-google-org-policy.json\n{\n  \"bindings\": [\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/artifactregistry.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/compute.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/container.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/dns.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/logging.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/resourcemanager.folderCreator\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/resourcemanager.folderIamAdmin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/resourcemanager.projectCreator\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/serviceusage.serviceUsageAdmin\"\n    }\n  ]\n}\nEOF\nread -p \"Enter NaaS Tenant Name [$NAAS_TENANTNAME]: \" TENANTNAME && \\\nexport NAAS_TENANTNAME=\"${TENANTNAME:-$NAAS_TENANTNAME}\" && \\\nsed -ie \"s/__TENANTNAME__/$NAAS_TENANTNAME/g\" naas-google-org-policy.json && \\\necho \"gcloud resource-manager folders set-iam-policy $NAAS_GOOGLE_FOLDERID naas-google-org-policy.json\"\n
    "},{"location":"technical/tenant-setup/#teams-part-1","title":"Teams (part 1)","text":"

    nais/teams-backend manages teams and configures groups and access in other systems.

    teams needs a dedicated user account in the Google directory. This user must be manually created in the Google Admin console. The user must be granted the Groups Admin role to be able to create and maintain groups for the teams:

    1. Go to https://admin.google.com/ac/users
    2. Click on Add new user
    3. Enter nais-teams as first name, and user as last name
    4. Enter nais-teams as the primary email
    5. Click Add new user to add the user account
    6. Click on the created user and then on Assign roles under the Admin roles and privileges section
    7. Assign the Groups Admin role and click Save
    "},{"location":"technical/tenant-setup/#teams-admins","title":"Teams admins","text":"

    teams automatically syncs users from the Google Workspace to its own database. Tenants can control which users that should be assigned the admin role in teams by creating a group called teams-admins@<tenant-domain>, and then add the necessary users to this group. When teams runs the user sync it will look for this group, and make sure that the users in the group are granted the admin role. Whenever a user is removed from the group, teams will revoke the admin role from the user on the next sync.

    Users with the admin role in teams have access to some parts of teams that regular users does not. Some of these features are:

    • Configure / enable / disable reconcilers
    • Grant / revoke roles
    • Manipulate reconciler states for teams
    "},{"location":"technical/tenant-setup/#kubernetes-group","title":"Kubernetes group","text":"

    In Google Admin create a group named gke-security-groups. This group is used to manage access to the kubernetes clusters, and will be managed by teams. Make sure the group has the View Members permission selected for Group Members.

    "},{"location":"technical/tenant-setup/#highly-recommended-settings","title":"Highly recommended settings","text":""},{"location":"technical/tenant-setup/#log-location","title":"Log location","text":"

    Every project created in GCP will have a default log location for all logs. The default is Global. In order to keep your logs in europe, we strongly recommend setting the default log location to europe using the following command

    gcloud alpha logging settings update --organization=<your org ID> --storage-location=europe-north1\n
    "},{"location":"technical/tenant-setup/#organization-policy-for-location","title":"Organization policy for location","text":"

    Although all resources created by NAIS is located within the EU, teams are still able to create resources anywhere unless an organizational constraint is in place.

    Click to see file content
    constraint: constraints/gcp.resourceLocations\netag: BwVUSr8Q7Ng=\nlistPolicy:\n  allowedValues:\n  - in:eu-locations\n
    gcloud beta resource-manager org-policies set-policy --organization=<your org ID> <file name>.yaml\n
    "},{"location":"technical/tenant-setup/#run-nais-terraform-modules","title":"Run nais-terraform-modules","text":"

    Before doing the following step, run the terraform setup.

    "},{"location":"technical/tenant-setup/#teams-part-2","title":"Teams (part 2)","text":""},{"location":"technical/tenant-setup/#configure-oauth-login-for-web-frontend","title":"Configure OAuth login for web frontend","text":"

    Set up an OAuth client for teams.

    1. Go to https://console.cloud.google.com
    2. Choose project -> nais-management -> nais-management
    3. Go to APIs ans Service -> OAuth consent screen
    4. Internal -> create
      1. App name: nais management
      2. User support email: admin@<tenant-domain>
      3. Developer Contact email: admin@<tenant-domain>
    5. Save and continue (x2)
    6. Go to APIs ans Service -> Credentials
    7. Click Create Credentials -> OAuth client ID
    8. Select type Web Application
      1. Name: teams
      2. Authorized redirect URI: http://teams.<tenant-name>.cloud.nais.io/oauth2/callback
    9. Set Name and Authorized redirect URIs
    10. Create
    11. Copy client id and secret and give to NAIS-team
    12. "},{"location":"technical/tenant-setup/#domain-wide-delegation","title":"Domain-wide Delegation","text":"

      teams performs some operations on behalf of the teams user mentioned above. For this to work the teams service account needs domain-wide delegation with some scopes. This must be manually set up in the Google Admin console:

      1. Go to https://admin.google.com/ac/owl/domainwidedelegation
      2. Click on Add new to add a new Client ID
      3. Enter the ID of the teams service account (provided by the NAIS team)
      4. Add the following scopes:
      5. https://www.googleapis.com/auth/admin.directory.group
      6. https://www.googleapis.com/auth/admin.directory.user.readonly
      7. Click on Authorize

      After this is done you should see something like the following:

      "},{"location":"technical/tenant-setup/#github-actions-secrets","title":"Github Actions secrets","text":"

      If you are using Github Actions to deploy your applications, you may want to add the following variable and secret to your organization's Github Actions secrets:

      Open https://github.com/organizations/[ORG_NAME]/settings/secrets/actions

      Name Type NAIS_MANAGEMENT_PROJECT_ID Variable NAIS_WORKLOAD_IDENTITY_PROVIDER Secret

      These may also be set in the repository's secrets, but it is recommended to set them in the organization's secrets as they are shared between all teams.

      The NAIS team will provide the values.

      "},{"location":"technical/tenant-setup/addons/azure-ad/","title":"Azure AD","text":"

      nais/azurerator creates and manages Azure AD applications via Kubernetes Custom Resources for use in various authentication scenarios.

      This is an optional addon in NaaS. It is not enabled by default.

      "},{"location":"technical/tenant-setup/addons/azure-ad/#for-tenant","title":"For Tenant","text":""},{"location":"technical/tenant-setup/addons/azure-ad/#requirements","title":"Requirements","text":"

      To be able to use this addon, you will need to bring your own Azure AD tenant.

      Unfortunately, we do not offer provisioning nor management of Azure AD itself as a service. The Azure AD tenant must be wholly owned and operated by your organization.

      You will also need to set up a couple of things within said tenant. We'll guide you through the steps.

      "},{"location":"technical/tenant-setup/addons/azure-ad/#google-service-accounts","title":"Google Service Accounts","text":"

      Azurerator uses federated credentials in order to authenticate itself to your Azure AD tenant, by using tokens issued by Google. This removes the need to share client secrets between our organizations. The tokens are in turn only issued to Google Service Accounts that exist within the NAIS projects that we've created for your Google organization.

      To set this up, you will need to find some identifiers from within your Google organization:

      1. Find the NAIS Google Project IDs:
        1. Use the gcloud CLI: gcloud projects list --filter=\"nais-\"
        2. There should be one project ID for each environment; nais-dev-xxxx and nais-prod-xxxx. Note these down.
      2. For each project ID, find the unique Service Account ID for Azurerator:
        1. gcloud iam service-accounts describe azurerator@<PROJECT_ID>.iam.gserviceaccount.com, where PROJECT_ID is the ID found in the previous step.
        2. Note down the uniqueId for the service account. This ID uniquely identifies the Google Service Account that Azurerator uses in each environment.
      "},{"location":"technical/tenant-setup/addons/azure-ad/#azure-ad-application-registration","title":"Azure AD Application Registration","text":"

      An Azure AD application registration within the tenant mentioned above is needed for Azurerator to create and manage application registrations within Azure AD.

      1. Sign in to your Azure Account through the Azure portal.
      2. Select Azure Active Directory.
      3. Select App registrations.
      4. Select New registration.
        1. Name the application, for example \"azurerator\".
        2. Supported account type doesn't matter, single tenant is fine.
        3. Leave Redirect URI empty.
      5. Under Overview, note down the values for the following fields:
        1. Application (client) ID.
        2. Directory (tenant) ID
      6. Navigate to Certificates and secrets.
        1. Select Federated credentials.
        2. Select Add credentials.
        3. Under Federated credential scenario, select Other issuer.
        4. Under Issuer, enter the value https://accounts.google.com
        5. Under Subject, enter the value for uniqueId that you noted down from the previous section on Google Service Accounts.
        6. Under Name, enter the value nais-<environment>, for example nais-dev or nais-prod
        7. Leave the Audience at the default value, i.e. api://AzureADTokenExchange
        8. Repeat the steps starting from step 6 with the second uniqueId from the previous section on Google Service Accounts.
      7. Navigate to API permissions.

        1. Select Add a permission.
        2. Select Microsoft Graph.
        3. Select Application permissions.
        4. The application needs the following permissions:
          • Application.ReadWrite.All
          • DelegatedPermissionGrant.ReadWrite.All
          • GroupMember.Read.All
        5. Add the permissions.
        6. Select Grant admin consent for <tenant name>.
        7. Confirm to grant the application access to the configured permissions.

        If done correctly, the list of permissions should look like this:

      "},{"location":"technical/tenant-setup/addons/azure-ad/#microsoft-graph-object-id","title":"Microsoft Graph Object ID","text":"

      In order for Azurerator to pre-approve delegated API permissions for the managed applications, you will need to find the Object ID for the Microsoft Graph Enterprise Application that is unique to each Azure AD tenant.

      1. Sign in to your Azure Account through the Azure portal.
      2. Select Azure Active Directory.
      3. Select Enterprise applications.
      4. Filter the list of applications:
        1. Applicaton ID starts with == \"00000003-0000-0000-c000-000000000000\"
        2. Application type == \"Microsoft Applications\"
      5. You should see an application named GraphAggregatorService or Microsoft Graph.
      6. Note down the Object ID for this application.
      "},{"location":"technical/tenant-setup/addons/azure-ad/#application-access-groups","title":"Application Access Groups","text":"

      Azurerator creates Azure AD application registrations that are restricted by default:

      • Users are not allowed access to the application unless they are explicitly given access.
      • Access is granted by group membership; groups are assigned directly to applications.
      • Users must be direct members of the groups, i.e. nested groups will not work.

      You will need to define a group that contains all users in your tenant. The definition of \"all users\" is left for you to decide. This can for example be:

      • all users, including guest accounts and machine users
      • all users that are not guests in your tenant
      • all users that have a valid license
      • all users within a certain department, and so on

      Refer to the following guides at Microsoft for details on groups:

      • creating and managing groups
      • dynamic group memberships

      The all users group will be assigned to any application that has enabled the allowAllUsers directive. Note down the object ID for this group.

      Once you've got through all of the above, provide the NAIS team with the following information:

      Property Description Tenant ID See Azure AD Application Registration Client ID See Azure AD Application Registration Microsoft Graph Object ID See Microsoft Graph Object ID Default All-Users Group Object ID See Application Access Groups"},{"location":"technical/tenant-setup/addons/azure-ad/#for-nais","title":"For NAIS","text":"
      1. Enter the required configuration for azurerator in Fasit, using the information given by the tenant
      2. Enable the azurerator feature in Fasit
      3. Enable the azurerator feature within naiserator in Fasit
      "},{"location":"technical/tenant-setup/addons/digdir/","title":"Digdirator","text":"

      Digdirator enabled

      This is an optional addon in NaaS. It is not enabled by default.

      Digdirator is a feature that integrates with Digdir self-service API. Digdirator enables automated registration and lifecycle management of ID-porten and Maskinporten clients.

      Before Digdirator can use the self-service API, the tenant must receive administration clients from Digdir, one for each client type, Maskinporten and ID-porten. The Digdir self-service API is secured with oAuth2 using a business certificate.

      An overview of the setup is as follows:

      • Clients exist in Digdir and a business certificate is configured
      • Clients are configured with scopes required
      • Add Client ID's to Secret Manager in your project
      • Add business certificate to Google Key Management Service in your project
      • Add business certificate certificate-chain to Secret Manager in your project
      "},{"location":"technical/tenant-setup/addons/digdir/#for-tenant","title":"For Tenant","text":""},{"location":"technical/tenant-setup/addons/digdir/#requirements","title":"Requirements","text":""},{"location":"technical/tenant-setup/addons/digdir/#digdir-configuration","title":"Digdir configuration","text":"Recommended configuration for administration clients

      To secure the integration with Digdir we recommend using a separate certificate for each registered client and that tenants request Digdir to lock each certificate to each client. If you already have a certificate for your clients, you can use that. As setup with these kinds of certificates is not part of this guide, we recommend that you contact Digdir for assistance.

      "},{"location":"technical/tenant-setup/addons/digdir/#configure-administration-clients-for-id-porten-maskinporten","title":"Configure administration clients for ID-porten & Maskinporten","text":"
      • ID-porten client is configured with scopes: idporten:dcr.write idporten:dcr.read
      • Maskinporten client is configured with scopes: idporten:dcr.write idporten:dcr.read idporten:scopes.write
      • business certificates are registered in Digdir

      Tenant imports the Client ID's to Secret Manager and provide the resource names to NAIS

      projects/<project-id>/secrets/<secret-id>/versions/<version>

      Digdirator use of Client ID

      Digdirator sets the Client ID as the claim iss when authenticating against Digdir self-service API

      "},{"location":"technical/tenant-setup/addons/digdir/#nais-configuration","title":"NAIS configuration","text":"

      We really care about our compadres (tenants) and we think that a separation of concerns is a good & secure way to go. It also helps us to keep the cluster secure and stable. The configuration setup for Digdirator favor security as NAIS never have direct access to your business certificate.

      When setup in Digdir is confirmed by tenant and before we can enable Digdirator, the following steps must be completed:

      "},{"location":"technical/tenant-setup/addons/digdir/#business-certificate","title":"Business certificate","text":"Update existing certificate

      Update of a certificate only requires the tenant to provide NAIS with the new <version>

      The tenant upload their business certificate to Google Cloud KMS. Digdirator will never have direct access to the certificate. Once it is uploaded the business certificate can only be used for cryptographic operations. The business certificate can never be downloaded or retrieved from the KMS storage.

      An authenticated & authorized Digdirator can only request the Google KMS to sign a payload containing an unsigned token with claims, if successful the KMS returns a signed JWT, this JWT is later used to authenticate against Digdir self-service API.

      Certificate is successfully uploaded to Google KMS, provide NAIS with the resource names

      projects/<project-id>/locations/<location>/keyRings/<keyring>/cryptoKeys/<key>/cryptoKeyVersions/<version>

      "},{"location":"technical/tenant-setup/addons/digdir/#certificate-chain","title":"Certificate chain","text":"Update existing certificate chain

      This information unlikely to change, only if a new certificate type is added to the Google KMS. Then the tenant must provide the new resource name or <version> of the certificate chain.

      Now your probably are wondering why another secret storage we already configured KMS?

      Well, when authenticating using a buissness certificate the oauth2.0 spec recommends the certificate chain to be present in the token header.

      The public certificate chain should be set to the x5c (X.509 certificate chain) header parameter, corresponding to the key used to digitally sign the JWS (JSON Web Signature).

      Google Cloud Key Mangement Service is designed as a cryptographic system: nobody, including yourself, can get the keys out: this means they're locked inside the system, and you don't have to worry in practice about them leaking. The tradeoff is that the only thing you can do with those keys is encrypting, decrypt, and other cryptographic operations.

      But when you do have configuration info like a certificate chain or a client-id, where your software actually needs the secret, not cryptographic operations, then Secret Manager is designed for that use case.

      Certificate chains is successfully uploaded to Secret Manager, provide NAIS with the resource names

      projects/<project-id>/secrets/<secret-id>/versions/<version>

      "},{"location":"technical/tenant-setup/addons/digdir/#example-format-of-a-certificate-chain","title":"Example format of a certificate chain","text":"
      -----BEGIN CERTIFICATE-----\nMIIFCDECEBC...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIE3sKEA...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFZTKK...\n-----END CERTIFICATE-----\n
      "},{"location":"technical/tenant-setup/addons/digdir/#for-nais","title":"For NAIS","text":"

      When Digdirator is enabled, NAIS configures Digdirator with a service account which holds a set of roles to access Google Cloud KMS and Secret Manager in your cluster project.

      To access Google KMS the service account is assigned the IAM role roles/cloudkms.signerVerifier, which enables sign, verify, and getPublicKey operations.

      Google Cloud KMS roles
      cloudkms.cryptoKeyVersions.useToSign\ncloudkms.cryptoKeyVersions.useToVerify\ncloudkms.cryptoKeyVersions.viewPublicKey\ncloudkms.locations.get\ncloudkms.locations.list\nresourcemanager.projects.get\n

      To access Secret Manager the service account is assigned the IAM role roles/secretmanager.secretAccessor which allows Digdirator to access the payload of secrets.

      Google Secret Manager roles
      secretmanager.secrets.get\nsecretmanager.secrets.access\nresourcemanager.projects.get\n

      NAIS will configure Digdirator with the information provided, you relax your cognitive load. Configure your NAIS application with ID-porten or Maskinporten, push code -> deploy. NAIS handles the rest.

      ID-porten sidecar

      If you plan to use the ID-porten sidecar, prior to usage, the feature Wonderwall must be enabled. Contact NAIS team for more information.

      "},{"location":"technical/tenant-setup/addons/digdir/#summary-of-nais-configuration","title":"Summary of NAIS configuration","text":"

      If we were to translate the above information required by NAIS to configure automated lifecycle of Digdir clients. Translated to yaml, it would look something like this

      maskinporten:\n  kms:\n    key: \"projects/123456789/locations/europe-north1/keyRings/nais-test/cryptoKeys/maskinporten-cert-chain/cryptoKeyVersions/1\"\n  secret-manager:\n    client-id: \"projects/123456789/secrets/maskinporten-client-id/versions/1\"\n    cert-cain: \"projects/123456789/secrets/maskinporten-cert-chain/versions/1\"\nidporten:\n  kms:\n    key: \"projects/123456789/locations/europe-north1/keyRings/nais-test/cryptoKeys/idporten-cert-chain/cryptoKeyVersions/1\"\n  secret-manager:\n    client-id: \"projects/123456789/secrets/idporten-client-id/versions/1\"\n    cert-cain: \"projects/123456789/secrets/idporten-cert-chain/versions/1\"\n
      "},{"location":"technical/tenant-setup/addons/digdir/#import-certificates","title":"Import Certificates","text":""},{"location":"technical/tenant-setup/addons/digdir/#pre-requisites","title":"Pre-requisites","text":"

      gcloud CLI is installed and configured with a user that have access to the project.

      Some configuration can be done in the Google Cloud Console, automatic wrap and import must be done with the gcloud CLI.

      "},{"location":"technical/tenant-setup/addons/digdir/#google-cloud-kms","title":"Google Cloud KMS","text":"
      1. Create a target key and key ring in your project
      2. Create a import job for the target key.
      3. Make an import request for key

      4. Wrap and import of key can be done in automatically or manually.

        • Automatically wrap and import with gcloud CLI
        • Manually is divided into 2 steps
          • Manually wrap using OpenSSL for Linux or macOS.
          • Manually import in the Google Cloud Console or gcloud CLI.
      "},{"location":"technical/tenant-setup/addons/digdir/#google-secret-manager","title":"Google Secret Manager","text":"
      • Create a secret in your project
      "},{"location":"technical/tenant-setup/addons/tokenx/","title":"TokenX","text":"

      TokenX is the short term for the OAuth 2.0 Token Exchange flow implemented in the context of Kubernetes.

      It primarily exists of:

      • an OAuth 2.0 Authorization server that provides applications with security tokens in order to securely communicate with each-other in a zero trust architecture.
      • a Kubernetes operator to register OAuth 2.0 clients and associated credentials with said Authorization Server.

      The intent of the token exchange flow is to ensure that the original subject's identity and permissions are propagated through a request chain of multiple applications, while maintaining security between each application.

      This is an optional addon in NaaS. It is not enabled by default.

      "},{"location":"technical/tenant-setup/addons/tokenx/#for-tenant","title":"For Tenant","text":"

      Provide the NAIS team with a list of URLs pointing to metadata documents for OAuth 2.0 / OpenID Connect compliant identity providers. This is often referred to as well-known URLs, typically ending in /.well-known/openid-configuration or /.well-known/oauth-authorization-server

      Otherwise, see TokenX for usage.

      "},{"location":"technical/tenant-setup/addons/tokenx/#for-nais-operators","title":"For NAIS operators","text":"
      1. Enter the tenant-provided well-known URL(s) in the Fasit configuration.
        • Enter the equivalent hosts for the outbound hosts needed for external access policies.
      2. Generate a set of public/private keypair in JWK format, e.g. through https://mkjwk.org/.
        • Specifications:
          • Key Type: RSA
          • Key Size: 2048
          • Key Usage: Signature
          • Algorithm: RS256
          • Key ID: SHA256
        • The private key is used by Jwker to sign JWT assertions to authenticate itself with Tokendings.
        • The public keyset (JWKS) is used by Tokendings to verify client assertions from Jwker.
      3. Enable Jwker in Naiserator.
      4. Enable the TokenX feature.
      "},{"location":"technical/tenant-setup/addons/wonderwall/","title":"Wonderwall","text":"

      Wonderwall is an application that handles OpenID Connect authentication as a sidecar to applications.

      This is an optional feature that is not enabled by default.

      "},{"location":"technical/tenant-setup/addons/wonderwall/#for-tenant","title":"For Tenant","text":""},{"location":"technical/tenant-setup/addons/wonderwall/#requirements-and-setup","title":"Requirements and Setup","text":"

      The tenant must bring its own identity provider.

      The tenant must set up a secret for each application that will use Wonderwall. The secret must fulfill the following:

      • Must be in the same namespace as the application
      • Must follow the naming convention login-config-<application-name>
      • Must contain the following keys:
      • WONDERWALL_OPENID_CLIENT_ID (e.g. my-client-id)
      • WONDERWALL_OPENID_CLIENT_JWK (e.g. {\"kty\":\"RSA\",\"e\":\"AQAB\",\"kid\":\"my-key-id\",...})
      • WONDERWALL_OPENID_WELL_KNOWN_URL (e.g. https://idp.example.com/.well-known/openid-configuration)
      "},{"location":"technical/tenant-setup/addons/wonderwall/#usage-by-applications","title":"Usage by Applications","text":"

      To use Wonderwall, the application must be configured to use the sidecar:

      spec:\n  login:\n    provider: openid\n

      The application must also be configured to allow external traffic to the identity provider:

      spec:\n  accessPolicy:\n    outbound:\n      external:\n        - host: <identity-provider-host>\n
      "},{"location":"technical/tenant-setup/addons/wonderwall/#for-nais","title":"For NAIS","text":""},{"location":"technical/tenant-setup/addons/wonderwall/#requirements","title":"Requirements","text":"
      • Aiven must be enabled for the tenant.
      "},{"location":"technical/tenant-setup/addons/wonderwall/#enable-the-wonderwall-feature-flag-in-naiserator","title":"Enable the Wonderwall feature flag in naiserator","text":""},{"location":"technical/tenant-setup/addons/wonderwall/#enable-the-wonderwall-feature-in-fasit","title":"Enable the Wonderwall feature in Fasit","text":"
      • Configure aiven.redisPlan
      • Enable openid.enabled
      • Disable azure.enabled
      • Disable idporten.enabled
      • Finally, enable the feature itself
      "},{"location":"welcome/nais-manifest-eng/","title":"NAIS is a AAAA rated platform service","text":"

      The As represent these qualities:

      • Autogenous: produced independently of external influence or aid
      • Advantageous: involving or creating favourable circumstances that increase the chances of success or effectiveness.
      • Automatic: working by itself with little or no direct human control.
      • Accountable: required or expected to justify actions or decisions.
      "},{"location":"welcome/nais-manifest-eng/#what-is-nais-for","title":"What is NAIS for?","text":"

      The NAIS platform is there for the development teams, and aims to offer the best conditions for developing quality welfare services for the Norwegian population. We do this by offering solid products that solve real problems at scale. The products are based on technology the nais team believes are technologically sustainable. By using the platform's products and following the platform standards, the teams can focus on solving high value challenges rather than underlying nuts and bolts. The two most important drivers for the further evolution of the platform are technological developments and the needs of the teams.

      "},{"location":"welcome/nais-manifest-eng/#what-motivates-us","title":"What motivates us?","text":""},{"location":"welcome/nais-manifest-eng/#social-mission","title":"Social mission","text":"

      We contribute to an important societal mission by developing and maintaining a platform that relieves developers and helps product teams succeed.

      "},{"location":"welcome/nais-manifest-eng/#colleagues","title":"Colleagues","text":"

      We have a good working environment with a positive energy consisting of colleagues who have the independence, passion, competence and will needed to solve our mission.

      "},{"location":"welcome/nais-manifest-eng/#autonomy","title":"Autonomy","text":"

      We have a great degree of freedom both as individuals and as a team. Within our assignment, we as a team choose which challenges we want to focus on and how we will solve these. As members of the team, we choose which tasks we want to participate in. This gives us a varied day to day life, and ownership of the things we work on.

      "},{"location":"welcome/nais-manifest-eng/#technology","title":"Technology","text":"

      At NAIS, we try to always choose the best tool for the job. We have a low threshold for experimentation, and are not afraid to ditch stuff that doesn't work. We take the advice of seasoned adventurers, but at the same time know that we can only make technology choices after building hands-on experience with the alternatives.

      "},{"location":"welcome/nais-manifest-eng/#what-are-we-optimizing-for","title":"What are we optimizing for?","text":"
      • Development speed

      • A first class developer experience

      • Easy to build secure applications

      • Easy to operate applications

      • Good ergonomics

      • Keep pace with new technology

      "},{"location":"welcome/nais-sponsor/","title":"NAIS-Sponsor","text":""},{"location":"welcome/nais-sponsor/#it-takes-a-village-to-raise-a-nais-developer","title":"It takes a village to raise a NAIS-developer","text":"

      For your NAIS-specific onboarding you will be guided by not only one sponsor, but you will be attached to the hip of every anchor so that you can gain insight into every as many aspects of NAIS as possible. When you have the general gist of things and feel ready you can just start picking tasks off the board(s).

      Not only the anchors are your sponsors. Every member of the team is - and you should not be apologetic or hold back in terms of reaching out to \"whomever\" because we have no higher priority than that you settle in and find joy and accomplishment with us. You can also attach yourself to anyone that you feel might shed more light on a topic you want to explore further.

      So if you find yourself wondering about something - keep this in mind: It is our duty (not to mention in our own best interest) to make sure you have the tools and understanding that you need so imagine that this Cronjob is run on the team every minute.

      "}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"A handbook of sorts","text":"

      Here we will cover the parts \"unique\" to us and therefore weren't covered during onboarding

      Nais is a complex animal - and if you are new to the team there will be quite a few things that are all but obvious and apparent.

      Factoids about the team are posted on Slack. Take a minute to present your facts, and find out about your colleagues.

      The technical documentation is comprehensive but hardly describes how we function as a team. This handbook is an attempt at bringing some of the silent knowledge to an audible frequency, and at the very least guide you through the bare essentials. To get you started we recommend that you familiarize yourself with our manifest. The guiding principles that define the how, the what, and the why we do the things that we do.

      So now that have you have memorized the manifest and documentation we can get into it all.

      "},{"location":"administrative/fixtures/","title":"Fixtures","text":"

      The NAIS team might look disorganised to a newcomer and in a certain sense of the word this holds true. However there are a few fixtures in place to ensure a certain degree of synchronisation, consensus and progression.

      "},{"location":"administrative/fixtures/#froom","title":"Froom","text":"

      Thanks to COVID19 we have become \"remote first only\". And in case you are wondering; The froom is our zoom based digital workspace. Froom is a portmanteau of Frode and Zoom. Frode is a popular guy, so his personal Zoom space was where we all gravitated.

      We all hang out in the lobby and join breakout rooms for more in-depth exploration of topics that may not be of general interest. Anyone is welcome anywhere but \"good manners\" apply. Make your presence known when joining and if you sense that you will be interupting trains of thought or coding flow, come back later or use Slack instead. The froom url is posted in the topic here.

      All meeting fixtures are held in The froom as well as ad-hoc and sceduled meetings with third parties.

      Any and all meetings that are deemed unnecessary due to priority or lack of substance are swiftly cancelled and we all go back to [insert task].

      "},{"location":"administrative/fixtures/#weekly","title":"Weekly","text":"

      The NAIS weekly takes place Monday at high noon.

      "},{"location":"administrative/slack/","title":"Slack","text":""},{"location":"administrative/slack/#we-do-not-want-to-leave-anyone-out-but-invites-and-inclusion-can-sometimes-fall-between-the-cracks","title":"We do not want to leave anyone out but invites and inclusion can sometimes fall between the cracks.","text":"

      Here is a list of Slack channels you might want to join (or in some cases should be in). If you haven't been invited to a private channel listed here let your sponsor know.

      "},{"location":"administrative/slack/#private-channels","title":"Private Channels","text":"

      #nais-internal #nais-tech

      "},{"location":"administrative/slack/#public-channels","title":"Public Channels","text":"

      #nais

      #naisdevice

      #nais-announcements

      "},{"location":"social/the-great-outdoors/","title":"The Great Outdoors","text":""},{"location":"social/the-great-outdoors/#all-work-and-no-play-makes-nais-a-dull-platform","title":"\"All work and no play makes NAIS a dull platform\"","text":""},{"location":"social/the-great-outdoors/#native-naisians","title":"Native NAISians","text":""},{"location":"social/the-great-outdoors/#the-nais-pole","title":"The NAIS Pole","text":""},{"location":"technical/doc-guidelines/","title":"NAIS documentation guidelines","text":"

      When writing the documentation we serve at doc.nais.io / doc.<tenant>.cloud.nais.io, we want to make sure that the content we provide helps our users to understand and use the platform we're making.

      Some key points to keep in mind when writing the docs are:

      • Following the diataxis theory
      • Less is more: Keep it short and to the point. This makes it easier to sustain high quality over time.
      • We are writing docs for the users of our platform. No one else. We should be empathetic to their needs and understanding of the platform, and be mindful of adding details that are not relevant in the current documentation context
      • Consistency in style and tone
      • NAIS Quality
      "},{"location":"technical/doc-guidelines/#structure","title":"Structure","text":"

      We structure our content primarily around what services NAIS provide, with some honest exceptions.

      Under each service, or category of services, we use Diataxis with the following convention:

      The main page for a service is an Explanation of the service. It should give a high-level overview of what the service is, why you would use it, and how it fits into the NAIS ecosystem.

      Example structure:

      some-service/\n\u251c\u2500 README.md # <- explanation\n\u251c\u2500 how-to/\n\u2502  \u251c\u2500 verb.md\n\u251c\u2500 reference/\n\u2502  \u251c\u2500 spec.md\n\u251c\u2500 .pages\n
      Collapsed reference structure

      If the service contains a single reference page, name the page README.md. This will collapse the directory structure in the navigation menu.

      "},{"location":"technical/doc-guidelines/#honest-exceptions","title":"Honest exceptions","text":"
      • Top-level explanations
      • Top-level tutorials
      • Operate: Here we describe the tools and services that are used and required to operate the platform
      • Tags overview
      • Legal stuff
      "},{"location":"technical/doc-guidelines/#pages-file","title":".pages file","text":"

      The .pages file is used to define overrides and customizations to the titles and order of the pages in the navigation menu. This is a feature of the Awesome Pages plugin for MkDocs.

      A conventional .pages file looks like this:

      .pages
      title: My overridden title\nnav:\n- README.md\n- \ud83d\udca1 Explanations: explanations\n- \ud83c\udfaf How-To: how-to\n- \ud83d\udcda Reference: reference\n- application\n- job\n- ...\n
      "},{"location":"technical/doc-guidelines/#conventions","title":"Conventions","text":""},{"location":"technical/doc-guidelines/#documentation-structure","title":"Documentation structure","text":"

      The file tree represents the structure of the navigation menu. The H1 (#) will be the title of the page and the title in the navigation menu

      To override the placement in the navigation menu, we use the Awesome Pages plugin for MkDocs.

      "},{"location":"technical/doc-guidelines/#placeholder-variables","title":"Placeholder variables","text":"

      Where the reader is expected to change the content, we use placeholder variables. These variables are written in uppercase, with words separated by hyphens, surrounded by <>. For example: <MY-APP>.

      "},{"location":"technical/doc-guidelines/#tenant-variables","title":"Tenant variables","text":"

      We template the tenant name in the documentation using <<tenant()>> When the documentation is built, this will be replaced with the relevant tenant name.

      For even more convenience, we have a <<tenant_url(\"service\")>> function that will replace the service with the relevant URL for the service and create a full tenant URL to the service. An optional second parameter can be used to specify the path to the service eg. <<tenant_url(\"grafana\", \"explore\")>>

      "},{"location":"technical/doc-guidelines/#tenant-specific-content","title":"Tenant-specific content","text":"

      Some sections are specific for a given tenant:

      page.md
      {%- if tenant() == \"nav\" %}\nTenant-specific content\n{%- endif %}\n

      ...or for multiple tenants:

      page.md
      {%- if tenant() in (\"nav\", \"dev-nais\") %}\nTenant-specific content\n{%- endif %}\n
      "},{"location":"technical/doc-guidelines/#tenant-specific-pages","title":"Tenant-specific pages","text":"

      If an entire page is specific to a tenant, specify the conditional field in the markdown front matter:

      page.md
      ---\nconditional: [tenant, <tenant-name>]\n---\n\n# Title\n\n...\n
      • tenant marks the page as tenant-specific.
      • <tenant-name> specifies which tenant that the page should be shown for.
      "},{"location":"technical/doc-guidelines/#code-blocks","title":"Code blocks","text":"

      When using code blocks, set the correct language for syntax highlighting. Define a title and highlight lines if needed.

      page.md
      ```yaml title=\"describe content / filename\" hl_lines=\"6-8 11\"\napiVersion: nais.io/v1alpha1\nkind: Application\n...\n```\n
      "},{"location":"technical/doc-guidelines/#alternate-paths","title":"Alternate paths","text":"

      When the user is given a choice, we want to show both paths in the documentation. For example programming language, OS or different methods

      page.md
      === \"Linux\"\n\n  linux specific stuff\n\n=== \"macOS\"\n\n  macOS specific stuff\n

      Indentation and blank lines

      Ensure you have tab indentation on the content block, as well as a blank line before and after.

      "},{"location":"technical/doc-guidelines/#links","title":"Links","text":"

      We want to make sure that the links are consistent and easy to understand. We use the following structure for links:

      Type of Link Icon Link Explanation [:bulb: Learn more about ...](../) How-to guide [:dart: Learn how to ...](../) Reference [:books: Reference for ](../) Tutorial [:rocket: Tutorial for ...](../) External link [:octicons-link-external-24: External link](https://...) Prometheus [:simple-prometheus: Open Prometheus](../) Grafana [:simple-grafana: Open Grafana](../)"},{"location":"technical/doc-guidelines/#gcp-only-features","title":"GCP only features","text":"

      Features that are only available in GCP clusters should preferably be marked in a consistent way.

      For that purpose, a macro is available to add a warning in the text:

      page.md
      # Aiven Redis\n\n<<gcp_only(\"Aiven Redis\")>>\n\nAiven Redis is ...\n
      "},{"location":"technical/doc-guidelines/#tags","title":"Tags","text":"

      We use tags to categorize and group the content to make it easier to find, as an alternative to the navigation menu and search.

      Tags are written in the front matter of the markdown file like so:

      page.md
      ---\ntags: [tag1, tag2]\n---\n\n# Title\n\n...\n
      "},{"location":"technical/doc-guidelines/#which-tags-should-i-use","title":"Which tags should I use?","text":"

      Tags should group multiple related pages together. Avoid using tags that only apply to a single page. This helps keeping the Tags-overview page cleaner.

      We typically always tag the diataxis-type the page classifies as with these mappings:

      Form Tag Explanation explanation How-to guide how-to Reference reference Tutorial tutorial

      Tag each page with the parent category or service that it belongs to.

      For example, these would be the tags for metrics and tracing in the observability category:

      observability/\n\u251c\u2500 README.md           # tags: [observability, explanation]\n\u251c\u2500 metrics/\n\u2502  \u251c\u2500 README.md        # tags: [observability, metrics, explanation]\n\u2502  \u251c\u2500 how-to/\n|  |  \u251c\u2500 how-to1.md    # tags: [metrics, how-to]\n|  \u251c\u2500 reference/\n\u2502  |  \u251c\u2500 spec.md       # tags: [metrics, reference]\n\u251c\u2500 tracing/\n\u2502  \u251c\u2500 README.md        # tags: [observability, tracing, explanation]\n\u2502  \u251c\u2500 how-to/\n|  |  \u251c\u2500 how-to1.md    # tags: [tracing, how-to]\n|  \u251c\u2500 reference/\n\u2502  |  \u251c\u2500 spec.md       # tags: [tracing, reference]\n
      "},{"location":"technical/doc-guidelines/#diataxis-httpsdiataxisfr","title":"Diataxis (https://diataxis.fr/)","text":"

      Di\u00e1taxis identifies four distinct needs, and four corresponding forms of documentation - tutorials, how-to guides, technical reference and explanation. It places them in a systematic relationship, and proposes that documentation should itself be organised around the structures of those needs.

      To create contents you must determine what you are setting out to do. Are you writing a Tutorial, a How-to guide, a Reference or is it a comprehensive Explanantion of a concept.

      "},{"location":"technical/doc-guidelines/#tutorial","title":"Tutorial","text":"

      A tutorial is an experience that takes place under the guidance of a tutor. A tutorial is always learning-oriented.

      "},{"location":"technical/doc-guidelines/#how-to","title":"How-to","text":"

      How-to guides are directions that guide the reader through a problem or towards a result. How-to guides are goal-oriented.

      "},{"location":"technical/doc-guidelines/#reference","title":"Reference","text":"

      Reference guides are technical descriptions of the machinery and how to operate it. Reference material is information-oriented.

      "},{"location":"technical/doc-guidelines/#explanation","title":"Explanation","text":"

      Explanation is a discusive treatment of a subject, that permits reflection. Explanation is understanding-oriented.

      "},{"location":"technical/external-ingress/","title":"External ingress","text":"

      We support adding external ingresses that other controls using cert-manager. This is easily done by adding a CNAME record pointing to an ingress we control.

      Read more about delegated domains for dns01 at cert-manager.io/docs.

      Underneath I've written the steps needed to take for us to get this working.

      "},{"location":"technical/external-ingress/#getting-external-ingress-up-and-running","title":"Getting external ingress up and running","text":"

      I'm going to use detsombetyrnoe.no as an example.

      1. Ask the secops team do add the following to the domain

        _acme-challenge.detsombetyrnoe.no  IN  CNAME  _acme-challenge.detsombetyrnoe.inter.nav.no.\n
      2. Create an Kubernetes Issuer:

        apiVersion: cert-manager.io/v1\nkind: Issuer\nmetadata:\n  name: detsombetyrnoe-no\n  namespace: nais-system\nspec:\n  acme:\n    email: frode.sundby@nav.no\n    preferredChain: ISRG Root X1\n    privateKeySecretRef:\n      name: cloud-nais-io-account-key\n    server: https://acme-v02.api.letsencrypt.org/directory\n    solvers:\n    - selector:\n        dnsZones:\n          - detsombetyrnoe.no\n      dns01:\n        cnameStrategy: Follow\n        cloudDNS:\n          hostedZoneName: intern-nav-no\n          project: nais-prod-020f\n

        You can use dnsName if you don't have subdomains, or if you want to be explicit.

      3. Then create a Kubernetes Certificate:

        apiVersion: cert-manager.io/v1\nkind: Certificate\nmetadata:\n  name: wc-detsombetyrnoe-no\n  namespace: nais-system\nspec:\n  dnsNames:\n  - detsombetyrnoe.no\n  - '*.detsombetyrnoe.no'\n  issuerRef:\n    name: detsombetyrnoe-no\n  secretName: wc-detsombetyrnoe-no-tls\n
      4. After the certificate has been approved by Let's encrypt, you need to notify loadbalancer about your certificate secret wc-detsombetyrnoe-no-tls. Go to Fasit > Your env > loadbalancer, and add your secret name to the Certificates list.

      5. Then you need to inform Naiserator about the new ingress, detsombetyrnoe.no. Go to Fasit > Your env > Naiserator, and add your secret name to the Extra external hosts list.
      6. Ask the user to add their new ingress to their nais.yaml.
      7. Success?
      "},{"location":"technical/external-ingress/#subdomains-yeah-but-manually","title":"Subdomains? Yeah, but manually...","text":"

      This solution also supports subdomains, but we need the secops team to add each subdomain as an _acme_challenge.

      _acme-challenge.www.detsombetyrnoe.no\tIN\tCNAME\t_acme-challenge.detsombetyrnoe.intern.nav.no.\n

      PS: Make sure there are not other issuer with the tag: issuewild!

      "},{"location":"technical/observability/","title":"Observability Stack","text":"

      This document describes the technical observability stack for nais-system Features.

      "},{"location":"technical/observability/#overview","title":"Overview","text":"

      The observability stack in nais consists of the following components:

      • Alertmanager
      • Grafana
      • Grafana Agent
      • Logging Operator
      • Loki
      • OpenTelemery Operator
      • OpenTelemetry Collector
      • Prometheus Operator
      • Prometheus
      • Tempo
      "},{"location":"technical/observability/#opentelemetry-collector","title":"OpenTelemetry Collector","text":"

      The OpenTelemetry Collector is a vendor-agnostic, open-source telemetry collector that can be used to collect, process, and export telemetry data. It is a powerful tool that can be used to collect logs, metrics, and traces from a variety of sources and export them to a variety of destinations.

      OpenTelemetry Collector implements the OpenTelemetry protocol (OTLP) which is a standard for transmitting telemetry data.

      Full otlpTraces only
      graph LR\n  Feature[Feature]\n  OtelCollector[Collector]\n  Loki\n  Prometheus\n  Tempo\n\n  Feature -- otlp --> OtelCollector\n\n  OtelCollector -- traces --> Tempo\n  OtelCollector -- logs --> Loki\n  OtelCollector -- metrics --> Prometheus\n\n  Tempo -- query --> Grafana\n  Loki -- query --> Grafana\n  Prometheus -- query --> Grafana
      graph LR\n  Feature[Feature]\n  OtelCollector[Collector]\n  LoggingOperator\n  Loki\n  Prometheus\n  Tempo\n\n  Feature -- traces --> OtelCollector\n  Feature -- stdout/stderr --> LoggingOperator\n  LoggingOperator -- forward --> Loki\n  Feature -- scrape --> Prometheus\n  OtelCollector -- traces --> Tempo\n\n  Tempo -- query --> Grafana\n  Loki -- query --> Grafana\n  Prometheus -- query --> Grafana
      "},{"location":"technical/observability/#endpoints","title":"Endpoints","text":"

      The OpenTelemetry Collector exposes the following endpoints:

      Endpoint Description http://opentelemetry-management-collector:4317 Internal endpoint for features in nais-system namespace. https://collector-internet.<tenant>.cloud.nais.io Internet exposed endpoint for things running outside of nais.

      Fasit features can use environment values in Feature.yaml to get the correct OpenTelemetry config without hardcoding the endpoint.

      Feature.yaml
      values:\n  observability.otelp.endpoint:\n    computed:\n      template: \"{{ .Env.otel_otlp_endpoint }}\"\n  observability.otelp.protocol:\n    computed:\n      template: \"{{ .Env.otel_otlp_protocol }}\"\n  observability.otelp.insecure:\n    computed:\n      template: \"{{ .Env.otel_otlp_insecure }}\"\n
      "},{"location":"technical/observability/#tenant-clusters","title":"Tenant Clusters","text":"

      All nais clusters have a dedicated OpenTelemetry Collector instance running in the nais-system. Tenant clusters forwards to management cluster using the otlp-http endpoint so that all telemetry data from nais-system is collected in a single place.

      ---\nconfig:\n    flowchart:\n        defaultRenderer: elk\n---\n%%{init: {'theme':'dark'}}%%\nflowchart\n  subgraph \"management\"[Management Cluster]\n    subgraph \"management-nais-system\"[nais-system]\n      OtelCollector[Management Collector]\n      Tempo\n      Loki\n      Prometheus\n      Feature[Feature]\n    end\n  end\n\n  subgraph \"dev\"[Tenant Dev Cluster]\n    subgraph \"dev-nais-system\"[nais-system]\n      DevFeature[Feature]\n      DevOtelC[Management Collector]\n    end\n  end\n\n  subgraph \"prod\"[Tenant Prod Cluster]\n    subgraph \"prod-nais-system\"[nais-system]\n      ProdFeature[Feature]\n      ProdOtelC[Management Collector]\n    end\n  end\n\n  Feature -- otlp-grpc --> OtelCollector\n\n  DevFeature -- otlp-grpc --> DevOtelC\n  ProdFeature -- otlp-grpc --> ProdOtelC\n  DevOtelC -- otlp-http --> OtelCollector\n  ProdOtelC -- otlp-http --> OtelCollector\n\n  OtelCollector -- traces --> Tempo\n  OtelCollector -- logs --> Loki\n  OtelCollector -- metrics --> Prometheus
      "},{"location":"technical/overview/","title":"NAIS Overview","text":"

      This document is a high-level overview of the NAIS platform

      "},{"location":"technical/overview/#namespaces","title":"Namespaces","text":"

      Over the years we have a number of namespaces that we use for different purposes. The ones to know about are:

      Name Description nais-system Where we deliver NAIS functionality nais Team namespace for NAIS. Custom functionality for NAV nais-verification Test applications for verifying NAIS with alerts kyverno Only Kyverno is allowed in here cnrm-system Where Cloud Native Resource Manager runs. Managed by Google"},{"location":"technical/overview/#tenants","title":"Tenants","text":""},{"location":"technical/overview/#clusters","title":"Clusters","text":""},{"location":"technical/overview/#management","title":"Management","text":""},{"location":"technical/production-ready/","title":"What is production ready?","text":"

      This is the NAIS team's attempt to define what production ready means to us. Production implies quality and durability. Running a system means serving requests, and requests are ultimately serving users. We care about our users, thus we must care about our systems.

      At NAIS, we strive to:

      • provide fully self serviced products with minimal downtime,
      • be confident that code changes will not break existing functionality,
      • respond quickly when systems fail,
      • spend minimal time fixing errors,
      • and most importantly: spend as much time possible implementing useful services for our users. (you!)

      We believe that if our systems conform to the principles in this document, we have a greater chance of achieving these goals.

      "},{"location":"technical/production-ready/#12-factor-app","title":"12 factor app","text":"

      Write your application according to the principles of 12 factor apps.

      Twelve factor apps:

      • have declarative system requirements,
      • are suitable for deployment in Docker containers,
      • do not have differences between development and production, and
      • can scale up without significant changes to tooling, architecture, or development practices.
      "},{"location":"technical/production-ready/#observability","title":"Observability","text":"

      Expose a Prometheus metric endpoint to allow scraping of key application metrics.

      "},{"location":"technical/production-ready/#measuring-success","title":"Measuring success","text":"

      Figure out service level indicators (SLI) and service level objectives (SLO).

      Service level indicators are quantifying metrics such as error rate, request latency, availability, and system throughput.

      Service level objectives are targets values for your metrics. You might say that you want an uptime of 99.9%. How do you define uptime? Is it a sufficiently low error rate? Is it being able to serve requests within a reasonable amount of time?

      Implement SLIs in the application code. Create views in a Grafana dashboard to check up on SLOs.

      Recommended read: Service Level Objectives in the Google Site Reliability Engineering handbook.

      "},{"location":"technical/production-ready/#alerts","title":"Alerts","text":"

      Alerts should be tied to SLOs. Consider if alerting is at all needed. An alert should only fire if human intervention is required. Too many alerts going off will result in alarm fatigue.

      "},{"location":"technical/production-ready/#relevant-logs","title":"Relevant logs","text":"

      Ensure traceability of errors by logging sufficient amount of debug information. Do not include sensitive data in logs. Sensitive data include credentials and personally identifyable information.

      "},{"location":"technical/production-ready/#tests","title":"Tests","text":"

      Ensure sufficient test coverage so that the next developer is not afraid of breaking things when updating your code.

      "},{"location":"technical/production-ready/#documentation","title":"Documentation","text":"
      • Development/building
      • End-user documentation
      • Sysadmin/maintenance
      • Document code where it is complex, hard to read, or otherwise obscure
      "},{"location":"technical/production-ready/#continuous-integration","title":"Continuous Integration","text":"

      Ensure that changes to the codebase are built automatically, and pushed to development and production environments. No manual steps other than git push should be neccessary.

      "},{"location":"technical/production-ready/#publish-and-announce","title":"Publish and announce","text":"

      Your system is not in production until it has users. Make sure all potential end users are aware of your system and can use it. Using a system means making requests and having access to support and documentation.

      "},{"location":"technical/production-ready/#decrease-bus-factor","title":"Decrease bus factor","text":"

      Ensure that at least two people on your team have sufficient knowledge to debug and work on the system, to avoid bus factor.

      "},{"location":"technical/production-ready/#data-protection-impact-assessment","title":"Data Protection Impact Assessment","text":"

      Perform, if applicable, a Data Protection Impact Assessment (or in Norwegian, personvernskonsekvensvurdering (PVK)).

      "},{"location":"technical/production-ready/#security-audit","title":"Security Audit","text":"

      Perform a security audit (ROS) before releasing to production.

      "},{"location":"technical/publications-media/","title":"Publications & Media","text":""},{"location":"technical/publications-media/#seasoned-adventurers-giving-back","title":"Seasoned adventurers - giving back","text":"

      Our work is in large part driven by and on open source solutions and thanks to the sharing of others we enjoy a faster pace and more robust infrastructure than one might otherwise expect. With that in mind, we do try to contribute with content that describe topics and experiences that have been or are of significance. Being a public service we also try to share through talks, conferences and interactions with other government bodies and the developer community in general. Here is a collection of the past & present.

      "},{"location":"technical/publications-media/#write-ups","title":"Write ups","text":"

      NAIS blog

      "},{"location":"technical/publications-media/#presentations","title":"Presentations","text":"
      • Using Kubernetes to Change Legacy Systems and Processes in the Public Sector

      • Experiences From Running Istio in a K8s Production Environment

      • NAIS applikasjonsplattform

      • Continious Monitoring

      • Hva kjennetegner en moderne applikasjonsplattform?

      "},{"location":"technical/upgrading-kafka/","title":"Procedure to follow when upgrading Kafka","text":"

      Kafka is an important service in NAV, and problems that affect Kafka affects many teams. For that reason we have decided to describe the procedure for upgrading Kafka in detail, to have a playlist to refer to.

      The upgrade should be properly announced in #nais-announcements, with a copy to relevant channels, either by link or by copied text. For NAV, #kafka is a relevant channel. For any other tenants that use Kafka, the tenant will typically have one support channel which should get a copy of the announcement.

      "},{"location":"technical/upgrading-kafka/#1-upgrade-in-dev-nais-dev-first","title":"1. Upgrade in dev-nais-dev first","text":"

      The dev-nais tenant is our testing tenant, and allows testing platform changes without affecting developer teams. By upgrading in dev-nais-dev first, we can check that kafka-canary continues to work, and optionally run additional tests to verify that everything works.

      It is considered enough to check that the kafka-canary continues to work and handles the upgrade process without major issues.

      Once everything is confirmed to work in dev-nais-dev, rolling out to ci-nais should be next.

      Upgrading is done by changing kafka_version in the naas.tf file for dev-nais tenant, dev environment.

      "},{"location":"technical/upgrading-kafka/#2-upgrade-the-ci-nais-tenant","title":"2. Upgrade the ci-nais tenant","text":"

      The ci-nais tenant is our CI tenant, and should emulate a production tenant as close as possible. Upgrading in ci-nais will allow us to check that the upgrade process works in a tenant that is more similar to production.

      Once everything is confirmed to work in ci-nais, rolling out to other tenants/clusters should be started as soon as possible.

      Upgrading is done by changing kafka_version in the naas.tf file for ci-nais tenant, ci environment.

      "},{"location":"technical/upgrading-kafka/#3-upgrade-development-environments","title":"3. Upgrade development environments","text":"

      Currently, NAV is the only tenant that uses Kafka, but we have one project that fall in this category:

      • nav-dev

      The upgrade should be announced clearly, with a request for teams to check their applications during the upgrade and after.

      Before starting the upgrade, it is recommended to silence some alerts that typically get triggered during the upgrade:

      • HighDiskReads
      • NetworkSentInbalanced
      • HighDiskUsagePredicted

      After the upgrade, teams will have 1 week to report any issues to the nais-team, who can decide if the upgrade in production should be held back or go ahead.

      Upgrading is done by changing/adding kafka_version in the naas.tf file for nav tenant, dev-gcp environment.

      "},{"location":"technical/upgrading-kafka/#4-upgrade-remaining-environments","title":"4. Upgrade remaining environments","text":"

      When announcing the upgrade, request that teams that haven't checked their dev environment do so now, and allow for a few hours before starting the upgrade. Make sure to dedicate time to watch the upgrade progress, and follow up on any reports of problems.

      Before starting the upgrade, it is recommended to silence some alerts that typically get triggered during the upgrade:

      • HighDiskReads
      • NetworkSentInbalanced
      • HighDiskUsagePredicted
      • HighDiskWrites
      • TODO: Find links for alerts in nav-infrastructure

      Make sure to inform the users when the upgrade has completed.

      Upgrading is done by changing the default value for the kafka_version variable in these files (and remove any tenant/environment specific values):

      • modules/aiven/variables.tf
      • modules/legacy/variables.tf
      • modules/tenant/variables.tf
      "},{"location":"technical/narcos/","title":"Narcos","text":"

      NAIS Adminstrator CLI Og Scripts

      "},{"location":"technical/narcos/#installation","title":"Installation","text":"

      brew install narco

      "},{"location":"technical/narcos/#usage","title":"Usage","text":"

      See available subcommands under the Reference section in the navigation sidebar.

      "},{"location":"technical/narcos/reference/cluster/","title":"cluster command","text":"

      The cluster command let you generate kubeconfig, and list clusters available for you.

      "},{"location":"technical/narcos/reference/cluster/#kubeconfig","title":"kubeconfig","text":"

      Create a kubeconfig file for connecting to available clusters for you. This requires that you have the gcloud command line tool installed, configured and logged in. You can log in with gcloud auth login --update-adc.

      narc kubeconfig\n
      Flag Short Description overwrite Overwrite config already in the kubeconfig-file clean Delete config before retrieving new one verbose -v More output, mostly useful combined with overwrite"},{"location":"technical/narcos/reference/cluster/#list","title":"list","text":"

      List clusters available.

      narc cluster list\n
      "},{"location":"technical/narcos/reference/tenant/","title":"tenant command","text":"

      The tenant command let you list, get, and set tenant for your Naisdevice.

      "},{"location":"technical/narcos/reference/tenant/#list","title":"list","text":"

      List tenants available.

      narc tenant list\n
      "},{"location":"technical/narcos/reference/tenant/#get","title":"get","text":"

      Get your current tenant.

      narc tenant get\n
      "},{"location":"technical/narcos/reference/tenant/#set","title":"set","text":"

      Switches your tenant to the one specified. May require that you log in.

      narc tenant set TENANT\n
      "},{"location":"technical/tenant-setup/","title":"Setting up a tenant organization","text":"

      This guide is used when setting up a new tenant. This is typically done by the NAIS team, together with the tenants administrators.

      graph TD\nA[Google Tenant] --> B[NAIS Folder]\nB --> C[management]\nB --> D[dev]\nB --> E[prod]
      "},{"location":"technical/tenant-setup/#prereq","title":"Prereq","text":"
      • Google Cloud Tenant admin
      • GitHub Organization
      "},{"location":"technical/tenant-setup/#required-settings","title":"Required settings","text":""},{"location":"technical/tenant-setup/#required-permissions","title":"Required permissions","text":"

      On the user that will run the following commands, the following IAM roles are required on an organization level.

      • Owner
      • Organization Administrator
      • Folder Creator
      • Organization Policy Administrator
      "},{"location":"technical/tenant-setup/#create-the-nais-folder","title":"Create the NAIS folder","text":"

      Everything related to NAIS is contained within this folder.

      export NAAS_ORG_NAME=my-org # (1)\nexport NAAS_ORG_ID=$(gcloud organizations list --filter $NAAS_ORG_NAME | tail -n1 | awk '{print $2}')\n\ngcloud resource-manager folders create --display-name=nais --organization=$NAAS_ORG_ID\nexport NAAS_GOOGLE_FOLDERID=$(gcloud resource-manager folders list --organization=$NAAS_ORG_ID | grep nais | awk '{print $3}')\n
      1. Change this to the name of your Google Organization
      "},{"location":"technical/tenant-setup/#grant-access-to-the-nais-team-and-the-terraform-user","title":"Grant access to the NAIS team and the terraform user","text":"

      To allow the NAIS team the required permissions to operate nais, IAM policies must be added to the NAIS folder.

      Bug

      Find correct roles for the following users:

      • nais-viewers
      • nais-admins
      Copy and run this command
      cat <<EOF > naas-google-org-policy.json\n{\n  \"bindings\": [\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/artifactregistry.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/compute.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/container.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/dns.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/logging.admin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/resourcemanager.folderCreator\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/resourcemanager.folderIamAdmin\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/resourcemanager.projectCreator\"\n    },\n    {\n      \"members\": [\n        \"serviceAccount:nais-tf-__TENANTNAME__@nais-io.iam.gserviceaccount.com\"\n      ],\n      \"role\": \"roles/serviceusage.serviceUsageAdmin\"\n    }\n  ]\n}\nEOF\nread -p \"Enter NaaS Tenant Name [$NAAS_TENANTNAME]: \" TENANTNAME && \\\nexport NAAS_TENANTNAME=\"${TENANTNAME:-$NAAS_TENANTNAME}\" && \\\nsed -ie \"s/__TENANTNAME__/$NAAS_TENANTNAME/g\" naas-google-org-policy.json && \\\necho \"gcloud resource-manager folders set-iam-policy $NAAS_GOOGLE_FOLDERID naas-google-org-policy.json\"\n
      "},{"location":"technical/tenant-setup/#teams-part-1","title":"Teams (part 1)","text":"

      nais/teams-backend manages teams and configures groups and access in other systems.

      teams needs a dedicated user account in the Google directory. This user must be manually created in the Google Admin console. The user must be granted the Groups Admin role to be able to create and maintain groups for the teams:

      1. Go to https://admin.google.com/ac/users
      2. Click on Add new user
      3. Enter nais-teams as first name, and user as last name
      4. Enter nais-teams as the primary email
      5. Click Add new user to add the user account
      6. Click on the created user and then on Assign roles under the Admin roles and privileges section
      7. Assign the Groups Admin role and click Save
      "},{"location":"technical/tenant-setup/#teams-admins","title":"Teams admins","text":"

      teams automatically syncs users from the Google Workspace to its own database. Tenants can control which users that should be assigned the admin role in teams by creating a group called teams-admins@<tenant-domain>, and then add the necessary users to this group. When teams runs the user sync it will look for this group, and make sure that the users in the group are granted the admin role. Whenever a user is removed from the group, teams will revoke the admin role from the user on the next sync.

      Users with the admin role in teams have access to some parts of teams that regular users does not. Some of these features are:

      • Configure / enable / disable reconcilers
      • Grant / revoke roles
      • Manipulate reconciler states for teams
      "},{"location":"technical/tenant-setup/#kubernetes-group","title":"Kubernetes group","text":"

      In Google Admin create a group named gke-security-groups. This group is used to manage access to the kubernetes clusters, and will be managed by teams. Make sure the group has the View Members permission selected for Group Members.

      "},{"location":"technical/tenant-setup/#highly-recommended-settings","title":"Highly recommended settings","text":""},{"location":"technical/tenant-setup/#log-location","title":"Log location","text":"

      Every project created in GCP will have a default log location for all logs. The default is Global. In order to keep your logs in europe, we strongly recommend setting the default log location to europe using the following command

      gcloud alpha logging settings update --organization=<your org ID> --storage-location=europe-north1\n
      "},{"location":"technical/tenant-setup/#organization-policy-for-location","title":"Organization policy for location","text":"

      Although all resources created by NAIS is located within the EU, teams are still able to create resources anywhere unless an organizational constraint is in place.

      Click to see file content
      constraint: constraints/gcp.resourceLocations\netag: BwVUSr8Q7Ng=\nlistPolicy:\n  allowedValues:\n  - in:eu-locations\n
      gcloud beta resource-manager org-policies set-policy --organization=<your org ID> <file name>.yaml\n
      "},{"location":"technical/tenant-setup/#run-nais-terraform-modules","title":"Run nais-terraform-modules","text":"

      Before doing the following step, run the terraform setup.

      "},{"location":"technical/tenant-setup/#teams-part-2","title":"Teams (part 2)","text":""},{"location":"technical/tenant-setup/#configure-oauth-login-for-web-frontend","title":"Configure OAuth login for web frontend","text":"

      Set up an OAuth client for teams.

      1. Go to https://console.cloud.google.com
      2. Choose project -> nais-management -> nais-management
      3. Go to APIs ans Service -> OAuth consent screen
      4. Internal -> create
        1. App name: nais management
        2. User support email: admin@<tenant-domain>
        3. Developer Contact email: admin@<tenant-domain>
      5. Save and continue (x2)
      6. Go to APIs ans Service -> Credentials
      7. Click Create Credentials -> OAuth client ID
      8. Select type Web Application
        1. Name: teams
        2. Authorized redirect URI: http://teams.<tenant-name>.cloud.nais.io/oauth2/callback
      9. Set Name and Authorized redirect URIs
      10. Create
      11. Copy client id and secret and give to NAIS-team
      12. "},{"location":"technical/tenant-setup/#domain-wide-delegation","title":"Domain-wide Delegation","text":"

        teams performs some operations on behalf of the teams user mentioned above. For this to work the teams service account needs domain-wide delegation with some scopes. This must be manually set up in the Google Admin console:

        1. Go to https://admin.google.com/ac/owl/domainwidedelegation
        2. Click on Add new to add a new Client ID
        3. Enter the ID of the teams service account (provided by the NAIS team)
        4. Add the following scopes:
        5. https://www.googleapis.com/auth/admin.directory.group
        6. https://www.googleapis.com/auth/admin.directory.user.readonly
        7. Click on Authorize

        After this is done you should see something like the following:

        "},{"location":"technical/tenant-setup/#github-actions-secrets","title":"Github Actions secrets","text":"

        If you are using Github Actions to deploy your applications, you may want to add the following variable and secret to your organization's Github Actions secrets:

        Open https://github.com/organizations/[ORG_NAME]/settings/secrets/actions

        Name Type NAIS_MANAGEMENT_PROJECT_ID Variable NAIS_WORKLOAD_IDENTITY_PROVIDER Secret

        These may also be set in the repository's secrets, but it is recommended to set them in the organization's secrets as they are shared between all teams.

        The NAIS team will provide the values.

        "},{"location":"technical/tenant-setup/addons/aiven/","title":"Aiven services and Kafka","text":"

        Aiven is a third party service provider that nais uses for some of the features we provide. If the tenant wishes to use some of those features, Aiven needs to be enabled for the tenant. The tenant does not need to have any interaction with Aiven directly, but the NAIS team will need to set up the necessary resources.

        Aiven provides these services:

        • Kafka (one per tenant environment)
        • OpenSearch (Created on-demand for each application)
        • Redis (Created on-demand for each application)

        This is an optional feature that is not enabled by default.

        "},{"location":"technical/tenant-setup/addons/aiven/#for-tenant","title":"For Tenant","text":""},{"location":"technical/tenant-setup/addons/aiven/#requirements-and-setup","title":"Requirements and Setup","text":"

        No preparation is required from the tenant.

        "},{"location":"technical/tenant-setup/addons/aiven/#usage-by-applications","title":"Usage by Applications","text":"

        Applications that wishes to use Kafka must configure the application:

        spec:\n  kafka:\n    pool: <tenant>-<environment>\n

        Relevant documentation for applications:

        • Kafka
        • OpenSearch
        • Redis
        "},{"location":"technical/tenant-setup/addons/aiven/#for-nais","title":"For NAIS","text":"
        • Enable Aiven for the tenant in nais-terraform-modules
        • If the tenant wishes to use Kafka, enable Kafka in nais-terraform-modules

        • After terraform has created the necessary Aiven resources, enable relevant features in Fasit (including required dependencies):

          • aiven-operator
          • mutilator
            • Optionally configure OpenTelemetry endpoint
          • aivenator
        • If Kafka is enabled, also enable these features:

          • kafka-canary
            • In management environment
          • kafkarator
          • aiven-alerts
          • kafka-canary-alert
          • kafka-lag-exporter
        "},{"location":"technical/tenant-setup/addons/azure-ad/","title":"Azure AD","text":"

        nais/azurerator creates and manages Azure AD applications via Kubernetes Custom Resources for use in various authentication scenarios.

        This is an optional addon in NaaS. It is not enabled by default.

        "},{"location":"technical/tenant-setup/addons/azure-ad/#for-tenant","title":"For Tenant","text":""},{"location":"technical/tenant-setup/addons/azure-ad/#requirements","title":"Requirements","text":"

        To be able to use this addon, you will need to bring your own Azure AD tenant.

        Unfortunately, we do not offer provisioning nor management of Azure AD itself as a service. The Azure AD tenant must be wholly owned and operated by your organization.

        You will also need to set up a couple of things within said tenant. We'll guide you through the steps.

        "},{"location":"technical/tenant-setup/addons/azure-ad/#google-service-accounts","title":"Google Service Accounts","text":"

        Azurerator uses federated credentials in order to authenticate itself to your Azure AD tenant, by using tokens issued by Google. This removes the need to share client secrets between our organizations. The tokens are in turn only issued to Google Service Accounts that exist within the NAIS projects that we've created for your Google organization.

        To set this up, you will need to find some identifiers from within your Google organization:

        1. Find the NAIS Google Project IDs:
          1. Use the gcloud CLI: gcloud projects list --filter=\"nais-\"
          2. There should be one project ID for each environment; nais-dev-xxxx and nais-prod-xxxx. Note these down.
        2. For each project ID, find the unique Service Account ID for Azurerator:
          1. gcloud iam service-accounts describe azurerator@<PROJECT_ID>.iam.gserviceaccount.com, where PROJECT_ID is the ID found in the previous step.
          2. Note down the uniqueId for the service account. This ID uniquely identifies the Google Service Account that Azurerator uses in each environment.
        "},{"location":"technical/tenant-setup/addons/azure-ad/#azure-ad-application-registration","title":"Azure AD Application Registration","text":"

        An Azure AD application registration within the tenant mentioned above is needed for Azurerator to create and manage application registrations within Azure AD.

        1. Sign in to your Azure Account through the Azure portal.
        2. Select Azure Active Directory.
        3. Select App registrations.
        4. Select New registration.
          1. Name the application, for example \"azurerator\".
          2. Supported account type doesn't matter, single tenant is fine.
          3. Leave Redirect URI empty.
        5. Under Overview, note down the values for the following fields:
          1. Application (client) ID.
          2. Directory (tenant) ID
        6. Navigate to Certificates and secrets.
          1. Select Federated credentials.
          2. Select Add credentials.
          3. Under Federated credential scenario, select Other issuer.
          4. Under Issuer, enter the value https://accounts.google.com
          5. Under Subject, enter the value for uniqueId that you noted down from the previous section on Google Service Accounts.
          6. Under Name, enter the value nais-<environment>, for example nais-dev or nais-prod
          7. Leave the Audience at the default value, i.e. api://AzureADTokenExchange
          8. Repeat the steps starting from step 6 with the second uniqueId from the previous section on Google Service Accounts.
        7. Navigate to API permissions.

          1. Select Add a permission.
          2. Select Microsoft Graph.
          3. Select Application permissions.
          4. The application needs the following permissions:
            • Application.ReadWrite.All
            • DelegatedPermissionGrant.ReadWrite.All
            • GroupMember.Read.All
          5. Add the permissions.
          6. Select Grant admin consent for <tenant name>.
          7. Confirm to grant the application access to the configured permissions.

          If done correctly, the list of permissions should look like this:

        "},{"location":"technical/tenant-setup/addons/azure-ad/#microsoft-graph-object-id","title":"Microsoft Graph Object ID","text":"

        In order for Azurerator to pre-approve delegated API permissions for the managed applications, you will need to find the Object ID for the Microsoft Graph Enterprise Application that is unique to each Azure AD tenant.

        1. Sign in to your Azure Account through the Azure portal.
        2. Select Azure Active Directory.
        3. Select Enterprise applications.
        4. Filter the list of applications:
          1. Applicaton ID starts with == \"00000003-0000-0000-c000-000000000000\"
          2. Application type == \"Microsoft Applications\"
        5. You should see an application named GraphAggregatorService or Microsoft Graph.
        6. Note down the Object ID for this application.
        "},{"location":"technical/tenant-setup/addons/azure-ad/#application-access-groups","title":"Application Access Groups","text":"

        Azurerator creates Azure AD application registrations that are restricted by default:

        • Users are not allowed access to the application unless they are explicitly given access.
        • Access is granted by group membership; groups are assigned directly to applications.
        • Users must be direct members of the groups, i.e. nested groups will not work.

        You will need to define a group that contains all users in your tenant. The definition of \"all users\" is left for you to decide. This can for example be:

        • all users, including guest accounts and machine users
        • all users that are not guests in your tenant
        • all users that have a valid license
        • all users within a certain department, and so on

        Refer to the following guides at Microsoft for details on groups:

        • creating and managing groups
        • dynamic group memberships

        The all users group will be assigned to any application that has enabled the allowAllUsers directive. Note down the object ID for this group.

        Once you've got through all of the above, provide the NAIS team with the following information:

        Property Description Tenant ID See Azure AD Application Registration Client ID See Azure AD Application Registration Microsoft Graph Object ID See Microsoft Graph Object ID Default All-Users Group Object ID See Application Access Groups"},{"location":"technical/tenant-setup/addons/azure-ad/#for-nais","title":"For NAIS","text":"
        1. Enter the required configuration for azurerator in Fasit, using the information given by the tenant
        2. Enable the azurerator feature in Fasit
        3. Enable the azurerator feature within naiserator in Fasit
        "},{"location":"technical/tenant-setup/addons/digdir/","title":"Digdirator","text":"

        Digdirator enabled

        This is an optional addon in NaaS. It is not enabled by default.

        Digdirator is a feature that integrates with Digdir self-service API. Digdirator enables automated registration and lifecycle management of ID-porten and Maskinporten clients.

        Before Digdirator can use the self-service API, the tenant must receive administration clients from Digdir, one for each client type, Maskinporten and ID-porten. The Digdir self-service API is secured with oAuth2 using a business certificate.

        An overview of the setup is as follows:

        • Clients exist in Digdir and a business certificate is configured
        • Clients are configured with scopes required
        • Add Client ID's to Secret Manager in your project
        • Add business certificate to Google Key Management Service in your project
        • Add business certificate certificate-chain to Secret Manager in your project
        "},{"location":"technical/tenant-setup/addons/digdir/#for-tenant","title":"For Tenant","text":""},{"location":"technical/tenant-setup/addons/digdir/#requirements","title":"Requirements","text":""},{"location":"technical/tenant-setup/addons/digdir/#digdir-configuration","title":"Digdir configuration","text":"Recommended configuration for administration clients

        To secure the integration with Digdir we recommend using a separate certificate for each registered client and that tenants request Digdir to lock each certificate to each client. If you already have a certificate for your clients, you can use that. As setup with these kinds of certificates is not part of this guide, we recommend that you contact Digdir for assistance.

        "},{"location":"technical/tenant-setup/addons/digdir/#configure-administration-clients-for-id-porten-maskinporten","title":"Configure administration clients for ID-porten & Maskinporten","text":"
        • ID-porten client is configured with scopes: idporten:dcr.write idporten:dcr.read
        • Maskinporten client is configured with scopes: idporten:dcr.write idporten:dcr.read idporten:scopes.write
        • business certificates are registered in Digdir

        Tenant imports the Client ID's to Secret Manager and provide the resource names to NAIS

        projects/<project-id>/secrets/<secret-id>/versions/<version>

        Digdirator use of Client ID

        Digdirator sets the Client ID as the claim iss when authenticating against Digdir self-service API

        "},{"location":"technical/tenant-setup/addons/digdir/#nais-configuration","title":"NAIS configuration","text":"

        We really care about our compadres (tenants) and we think that a separation of concerns is a good & secure way to go. It also helps us to keep the cluster secure and stable. The configuration setup for Digdirator favor security as NAIS never have direct access to your business certificate.

        When setup in Digdir is confirmed by tenant and before we can enable Digdirator, the following steps must be completed:

        "},{"location":"technical/tenant-setup/addons/digdir/#business-certificate","title":"Business certificate","text":"Update existing certificate

        Update of a certificate only requires the tenant to provide NAIS with the new <version>

        The tenant upload their business certificate to Google Cloud KMS. Digdirator will never have direct access to the certificate. Once it is uploaded the business certificate can only be used for cryptographic operations. The business certificate can never be downloaded or retrieved from the KMS storage.

        An authenticated & authorized Digdirator can only request the Google KMS to sign a payload containing an unsigned token with claims, if successful the KMS returns a signed JWT, this JWT is later used to authenticate against Digdir self-service API.

        Certificate is successfully uploaded to Google KMS, provide NAIS with the resource names

        projects/<project-id>/locations/<location>/keyRings/<keyring>/cryptoKeys/<key>/cryptoKeyVersions/<version>

        "},{"location":"technical/tenant-setup/addons/digdir/#certificate-chain","title":"Certificate chain","text":"Update existing certificate chain

        This information unlikely to change, only if a new certificate type is added to the Google KMS. Then the tenant must provide the new resource name or <version> of the certificate chain.

        Now your probably are wondering why another secret storage we already configured KMS?

        Well, when authenticating using a buissness certificate the oauth2.0 spec recommends the certificate chain to be present in the token header.

        The public certificate chain should be set to the x5c (X.509 certificate chain) header parameter, corresponding to the key used to digitally sign the JWS (JSON Web Signature).

        Google Cloud Key Mangement Service is designed as a cryptographic system: nobody, including yourself, can get the keys out: this means they're locked inside the system, and you don't have to worry in practice about them leaking. The tradeoff is that the only thing you can do with those keys is encrypting, decrypt, and other cryptographic operations.

        But when you do have configuration info like a certificate chain or a client-id, where your software actually needs the secret, not cryptographic operations, then Secret Manager is designed for that use case.

        Certificate chains is successfully uploaded to Secret Manager, provide NAIS with the resource names

        projects/<project-id>/secrets/<secret-id>/versions/<version>

        "},{"location":"technical/tenant-setup/addons/digdir/#example-format-of-a-certificate-chain","title":"Example format of a certificate chain","text":"
        -----BEGIN CERTIFICATE-----\nMIIFCDECEBC...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIE3sKEA...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFZTKK...\n-----END CERTIFICATE-----\n
        "},{"location":"technical/tenant-setup/addons/digdir/#for-nais","title":"For NAIS","text":"

        When Digdirator is enabled, NAIS configures Digdirator with a service account which holds a set of roles to access Google Cloud KMS and Secret Manager in your cluster project.

        To access Google KMS the service account is assigned the IAM role roles/cloudkms.signerVerifier, which enables sign, verify, and getPublicKey operations.

        Google Cloud KMS roles
        cloudkms.cryptoKeyVersions.useToSign\ncloudkms.cryptoKeyVersions.useToVerify\ncloudkms.cryptoKeyVersions.viewPublicKey\ncloudkms.locations.get\ncloudkms.locations.list\nresourcemanager.projects.get\n

        To access Secret Manager the service account is assigned the IAM role roles/secretmanager.secretAccessor which allows Digdirator to access the payload of secrets.

        Google Secret Manager roles
        secretmanager.secrets.get\nsecretmanager.secrets.access\nresourcemanager.projects.get\n

        NAIS will configure Digdirator with the information provided, you relax your cognitive load. Configure your NAIS application with ID-porten or Maskinporten, push code -> deploy. NAIS handles the rest.

        ID-porten sidecar

        If you plan to use the ID-porten sidecar, prior to usage, the feature Wonderwall must be enabled. Contact NAIS team for more information.

        "},{"location":"technical/tenant-setup/addons/digdir/#summary-of-nais-configuration","title":"Summary of NAIS configuration","text":"

        If we were to translate the above information required by NAIS to configure automated lifecycle of Digdir clients. Translated to yaml, it would look something like this

        maskinporten:\n  kms:\n    key: \"projects/123456789/locations/europe-north1/keyRings/nais-test/cryptoKeys/maskinporten-cert-chain/cryptoKeyVersions/1\"\n  secret-manager:\n    client-id: \"projects/123456789/secrets/maskinporten-client-id/versions/1\"\n    cert-cain: \"projects/123456789/secrets/maskinporten-cert-chain/versions/1\"\nidporten:\n  kms:\n    key: \"projects/123456789/locations/europe-north1/keyRings/nais-test/cryptoKeys/idporten-cert-chain/cryptoKeyVersions/1\"\n  secret-manager:\n    client-id: \"projects/123456789/secrets/idporten-client-id/versions/1\"\n    cert-cain: \"projects/123456789/secrets/idporten-cert-chain/versions/1\"\n
        "},{"location":"technical/tenant-setup/addons/digdir/#import-certificates","title":"Import Certificates","text":""},{"location":"technical/tenant-setup/addons/digdir/#pre-requisites","title":"Pre-requisites","text":"

        gcloud CLI is installed and configured with a user that have access to the project.

        Some configuration can be done in the Google Cloud Console, automatic wrap and import must be done with the gcloud CLI.

        "},{"location":"technical/tenant-setup/addons/digdir/#google-cloud-kms","title":"Google Cloud KMS","text":"
        1. Create a target key and key ring in your project
        2. Create a import job for the target key.
        3. Make an import request for key

        4. Wrap and import of key can be done in automatically or manually.

          • Automatically wrap and import with gcloud CLI
          • Manually is divided into 2 steps
            • Manually wrap using OpenSSL for Linux or macOS.
            • Manually import in the Google Cloud Console or gcloud CLI.
        "},{"location":"technical/tenant-setup/addons/digdir/#google-secret-manager","title":"Google Secret Manager","text":"
        • Create a secret in your project
        "},{"location":"technical/tenant-setup/addons/tokenx/","title":"TokenX","text":"

        TokenX is the short term for the OAuth 2.0 Token Exchange flow implemented in the context of Kubernetes.

        It primarily exists of:

        • an OAuth 2.0 Authorization server that provides applications with security tokens in order to securely communicate with each-other in a zero trust architecture.
        • a Kubernetes operator to register OAuth 2.0 clients and associated credentials with said Authorization Server.

        The intent of the token exchange flow is to ensure that the original subject's identity and permissions are propagated through a request chain of multiple applications, while maintaining security between each application.

        This is an optional addon in NaaS. It is not enabled by default.

        "},{"location":"technical/tenant-setup/addons/tokenx/#for-tenant","title":"For Tenant","text":"

        Provide the NAIS team with a list of URLs pointing to metadata documents for OAuth 2.0 / OpenID Connect compliant identity providers. This is often referred to as well-known URLs, typically ending in /.well-known/openid-configuration or /.well-known/oauth-authorization-server

        Otherwise, see TokenX for usage.

        "},{"location":"technical/tenant-setup/addons/tokenx/#for-nais-operators","title":"For NAIS operators","text":"
        1. Enter the tenant-provided well-known URL(s) in the Fasit configuration.
          • Enter the equivalent hosts for the outbound hosts needed for external access policies.
        2. Generate a set of public/private keypair in JWK format, e.g. through https://mkjwk.org/.
          • Specifications:
            • Key Type: RSA
            • Key Size: 2048
            • Key Usage: Signature
            • Algorithm: RS256
            • Key ID: SHA256
          • The private key is used by Jwker to sign JWT assertions to authenticate itself with Tokendings.
          • The public keyset (JWKS) is used by Tokendings to verify client assertions from Jwker.
        3. Enable Jwker in Naiserator.
        4. Enable the TokenX feature.
        "},{"location":"technical/tenant-setup/addons/wonderwall/","title":"Wonderwall","text":"

        Wonderwall is an application that handles OpenID Connect authentication as a sidecar to applications.

        This is an optional feature that is not enabled by default.

        "},{"location":"technical/tenant-setup/addons/wonderwall/#for-tenant","title":"For Tenant","text":""},{"location":"technical/tenant-setup/addons/wonderwall/#requirements-and-setup","title":"Requirements and Setup","text":"

        The tenant must bring its own identity provider.

        The tenant must set up a secret for each application that will use Wonderwall. The secret must fulfill the following:

        • Must be in the same namespace as the application
        • Must follow the naming convention login-config-<application-name>
        • Must contain the following keys:
        • WONDERWALL_OPENID_CLIENT_ID (e.g. my-client-id)
        • WONDERWALL_OPENID_CLIENT_JWK (e.g. {\"kty\":\"RSA\",\"e\":\"AQAB\",\"kid\":\"my-key-id\",...})
        • WONDERWALL_OPENID_WELL_KNOWN_URL (e.g. https://idp.example.com/.well-known/openid-configuration)
        "},{"location":"technical/tenant-setup/addons/wonderwall/#usage-by-applications","title":"Usage by Applications","text":"

        To use Wonderwall, the application must be configured to use the sidecar:

        spec:\n  login:\n    provider: openid\n

        The application must also be configured to allow external traffic to the identity provider:

        spec:\n  accessPolicy:\n    outbound:\n      external:\n        - host: <identity-provider-host>\n
        "},{"location":"technical/tenant-setup/addons/wonderwall/#for-nais","title":"For NAIS","text":""},{"location":"technical/tenant-setup/addons/wonderwall/#requirements","title":"Requirements","text":"
        • Aiven must be enabled for the tenant.
        "},{"location":"technical/tenant-setup/addons/wonderwall/#enable-the-wonderwall-feature-flag-in-naiserator","title":"Enable the Wonderwall feature flag in naiserator","text":""},{"location":"technical/tenant-setup/addons/wonderwall/#enable-the-wonderwall-feature-in-fasit","title":"Enable the Wonderwall feature in Fasit","text":"
        • Configure aiven.redisPlan
        • Enable openid.enabled
        • Disable azure.enabled
        • Disable idporten.enabled
        • Finally, enable the feature itself
        "},{"location":"welcome/nais-manifest-eng/","title":"NAIS is a AAAA rated platform service","text":"

        The As represent these qualities:

        • Autogenous: produced independently of external influence or aid
        • Advantageous: involving or creating favourable circumstances that increase the chances of success or effectiveness.
        • Automatic: working by itself with little or no direct human control.
        • Accountable: required or expected to justify actions or decisions.
        "},{"location":"welcome/nais-manifest-eng/#what-is-nais-for","title":"What is NAIS for?","text":"

        The NAIS platform is there for the development teams, and aims to offer the best conditions for developing quality welfare services for the Norwegian population. We do this by offering solid products that solve real problems at scale. The products are based on technology the nais team believes are technologically sustainable. By using the platform's products and following the platform standards, the teams can focus on solving high value challenges rather than underlying nuts and bolts. The two most important drivers for the further evolution of the platform are technological developments and the needs of the teams.

        "},{"location":"welcome/nais-manifest-eng/#what-motivates-us","title":"What motivates us?","text":""},{"location":"welcome/nais-manifest-eng/#social-mission","title":"Social mission","text":"

        We contribute to an important societal mission by developing and maintaining a platform that relieves developers and helps product teams succeed.

        "},{"location":"welcome/nais-manifest-eng/#colleagues","title":"Colleagues","text":"

        We have a good working environment with a positive energy consisting of colleagues who have the independence, passion, competence and will needed to solve our mission.

        "},{"location":"welcome/nais-manifest-eng/#autonomy","title":"Autonomy","text":"

        We have a great degree of freedom both as individuals and as a team. Within our assignment, we as a team choose which challenges we want to focus on and how we will solve these. As members of the team, we choose which tasks we want to participate in. This gives us a varied day to day life, and ownership of the things we work on.

        "},{"location":"welcome/nais-manifest-eng/#technology","title":"Technology","text":"

        At NAIS, we try to always choose the best tool for the job. We have a low threshold for experimentation, and are not afraid to ditch stuff that doesn't work. We take the advice of seasoned adventurers, but at the same time know that we can only make technology choices after building hands-on experience with the alternatives.

        "},{"location":"welcome/nais-manifest-eng/#what-are-we-optimizing-for","title":"What are we optimizing for?","text":"
        • Development speed

        • A first class developer experience

        • Easy to build secure applications

        • Easy to operate applications

        • Good ergonomics

        • Keep pace with new technology

        "},{"location":"welcome/nais-sponsor/","title":"NAIS-Sponsor","text":""},{"location":"welcome/nais-sponsor/#it-takes-a-village-to-raise-a-nais-developer","title":"It takes a village to raise a NAIS-developer","text":"

        For your NAIS-specific onboarding you will be guided by not only one sponsor, but you will be attached to the hip of every anchor so that you can gain insight into every as many aspects of NAIS as possible. When you have the general gist of things and feel ready you can just start picking tasks off the board(s).

        Not only the anchors are your sponsors. Every member of the team is - and you should not be apologetic or hold back in terms of reaching out to \"whomever\" because we have no higher priority than that you settle in and find joy and accomplishment with us. You can also attach yourself to anyone that you feel might shed more light on a topic you want to explore further.

        So if you find yourself wondering about something - keep this in mind: It is our duty (not to mention in our own best interest) to make sure you have the tools and understanding that you need so imagine that this Cronjob is run on the team every minute.

        "}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 67de8e12..de353de1 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -75,6 +75,11 @@ 2024-09-17 daily + + https://handbook.nais.io/technical/tenant-setup/addons/aiven/ + 2024-09-17 + daily + https://handbook.nais.io/technical/tenant-setup/addons/azure-ad/ 2024-09-17 diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 484d32e64c7c4e6a02499c5ed82eab0558a79942..5be7c77ae1eab62aab55be3ec3914c146135d5dc 100644 GIT binary patch delta 88 zcmV-e0H^=51GobQABzYG_(!n@Y5_sekJo(SY9_+*9uXW!4*&pDf-6S= delta 82 zcmV-Y0ImPH1F{1KABzYGct5cQY5_up-+J3J;CBc2)O$+1V`m;QUU$b{IeJVhgis)T o#o%~CyN%5Rkvf!YF!rTeW!AOj|FDTaANoPtKZO+SO_dG+0FWjmEdT%j diff --git a/social/the-great-outdoors/index.html b/social/the-great-outdoors/index.html index f5ef0567..f0927087 100644 --- a/social/the-great-outdoors/index.html +++ b/social/the-great-outdoors/index.html @@ -888,6 +888,8 @@ + + @@ -924,6 +926,27 @@ +
      13. + + + + + Aiven services and Kafka + + + + +
      14. + + + + + + + + + +
      15. @@ -1219,7 +1242,7 @@

        The NAIS Pole - 2024-09-17 + 2024-09-17 @@ -1229,7 +1252,7 @@

        The NAIS Pole - 2024-09-17 + 2024-09-17 diff --git a/technical/doc-guidelines/index.html b/technical/doc-guidelines/index.html index 8dd130a2..cfb876f5 100644 --- a/technical/doc-guidelines/index.html +++ b/technical/doc-guidelines/index.html @@ -1065,6 +1065,8 @@ + + @@ -1101,6 +1103,27 @@ +
      16. + + + + + Aiven services and Kafka + + + + +
      17. + + + + + + + + + +
      18. @@ -1801,7 +1824,7 @@

        Explanat - 2024-09-17 + 2024-09-17 @@ -1811,7 +1834,7 @@

        Explanat - 2024-09-17 + 2024-09-17 diff --git a/technical/external-ingress/index.html b/technical/external-ingress/index.html index 9fa6e4cc..d1f6844b 100644 --- a/technical/external-ingress/index.html +++ b/technical/external-ingress/index.html @@ -885,6 +885,8 @@ + + @@ -921,6 +923,27 @@ +
      19. + + + + + Aiven services and Kafka + + + + +
      20. + + + + + + + + + +
      21. @@ -1276,7 +1299,7 @@

        Subdomains? Yeah, but manually... - 2024-09-17 + 2024-09-17 @@ -1286,7 +1309,7 @@

        Subdomains? Yeah, but manually... - 2024-09-17 + 2024-09-17 diff --git a/technical/narcos/index.html b/technical/narcos/index.html index 26ddde94..9a1e9223 100644 --- a/technical/narcos/index.html +++ b/technical/narcos/index.html @@ -823,6 +823,8 @@ + + @@ -859,6 +861,27 @@ +
      22. + + + + + Aiven services and Kafka + + + + +
      23. + + + + + + + + + +
      24. @@ -1145,7 +1168,7 @@

        Usage& - 2024-09-17 + 2024-09-17 @@ -1155,7 +1178,7 @@

        Usage& - 2024-09-17 + 2024-09-17 diff --git a/technical/narcos/reference/cluster/index.html b/technical/narcos/reference/cluster/index.html index 8b4ef1d5..7af8049b 100644 --- a/technical/narcos/reference/cluster/index.html +++ b/technical/narcos/reference/cluster/index.html @@ -883,6 +883,8 @@ + + @@ -919,6 +921,27 @@ +
      25. + + + + + Aiven services and Kafka + + + + +
      26. + + + + + + + + + +
      27. @@ -1237,7 +1260,7 @@

        list&par - 2024-09-17 + 2024-09-17 @@ -1247,7 +1270,7 @@

        list&par - 2024-09-17 + 2024-09-17 diff --git a/technical/narcos/reference/tenant/index.html b/technical/narcos/reference/tenant/index.html index 0ae3acec..d3676c77 100644 --- a/technical/narcos/reference/tenant/index.html +++ b/technical/narcos/reference/tenant/index.html @@ -892,6 +892,8 @@ + + @@ -928,6 +930,27 @@ +
      28. + + + + + Aiven services and Kafka + + + + +
      29. + + + + + + + + + +
      30. @@ -1232,7 +1255,7 @@

        set¶< - 2024-09-17 + 2024-09-17 @@ -1242,7 +1265,7 @@

        set¶< - 2024-09-17 + 2024-09-17 diff --git a/technical/observability/index.html b/technical/observability/index.html index 7f318803..55ca6e9e 100644 --- a/technical/observability/index.html +++ b/technical/observability/index.html @@ -903,6 +903,8 @@ + + @@ -939,6 +941,27 @@ +
      31. + + + + + Aiven services and Kafka + + + + +
      32. + + + + + + + + + +
      33. @@ -1381,7 +1404,7 @@

        Tenant Clusters - 2024-09-17 + 2024-09-17 @@ -1391,7 +1414,7 @@

        Tenant Clusters - 2024-09-17 + 2024-09-17 diff --git a/technical/overview/index.html b/technical/overview/index.html index cc4ea342..9570d779 100644 --- a/technical/overview/index.html +++ b/technical/overview/index.html @@ -897,6 +897,8 @@ + + @@ -933,6 +935,27 @@ +
      34. + + + + + Aiven services and Kafka + + + + +
      35. + + + + + + + + + +
      36. @@ -1268,7 +1291,7 @@

        Management - 2024-09-17 + 2024-09-17 @@ -1278,7 +1301,7 @@

        Management - 2024-09-17 + 2024-09-17 diff --git a/technical/production-ready/index.html b/technical/production-ready/index.html index ca0e0274..51e7178c 100644 --- a/technical/production-ready/index.html +++ b/technical/production-ready/index.html @@ -969,6 +969,8 @@ + + @@ -1005,6 +1007,27 @@ +
      37. + + + + + Aiven services and Kafka + + + + +
      38. + + + + + + + + + +
      39. @@ -1446,7 +1469,7 @@

        Security Audit - 2024-09-17 + 2024-09-17 @@ -1456,7 +1479,7 @@

        Security Audit - 2024-09-17 + 2024-09-17 diff --git a/technical/publications-media/index.html b/technical/publications-media/index.html index ce56039b..a94254fa 100644 --- a/technical/publications-media/index.html +++ b/technical/publications-media/index.html @@ -888,6 +888,8 @@ + + @@ -924,6 +926,27 @@ +
      40. + + + + + Aiven services and Kafka + + + + +
      41. + + + + + + + + + +
      42. @@ -1240,7 +1263,7 @@

        Presentations - 2024-09-17 + 2024-09-17 @@ -1250,7 +1273,7 @@

        Presentations - 2024-09-17 + 2024-09-17 diff --git a/technical/tenant-setup/addons/aiven/index.html b/technical/tenant-setup/addons/aiven/index.html new file mode 100644 index 00000000..0c41f47a --- /dev/null +++ b/technical/tenant-setup/addons/aiven/index.html @@ -0,0 +1,1490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Aiven services and Kafka - NAIS Handbook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + +
        + + + + + + +
        + + +
        + +
        + + + + + + +
        +
        + + + +
        +
        +
        + + + + + +
        +
        +
        + + + +
        +
        +
        + + + +
        +
        +
        + + + +
        +
        + + + + + + + + + + + + +

        Aiven services and Kafka

        +

        Aiven is a third party service provider that nais uses for some of the features we provide. +If the tenant wishes to use some of those features, Aiven needs to be enabled for the tenant. +The tenant does not need to have any interaction with Aiven directly, but the NAIS team will need to set up the +necessary resources.

        +

        Aiven provides these services:

        +
          +
        • Kafka (one per tenant environment)
        • +
        • OpenSearch (Created on-demand for each application)
        • +
        • Redis (Created on-demand for each application)
        • +
        +

        This is an optional feature that is not enabled by default.

        +

        For Tenant

        +

        Requirements and Setup

        +

        No preparation is required from the tenant.

        +

        Usage by Applications

        +

        Applications that wishes to use Kafka must configure the application:

        +
        spec:
        +  kafka:
        +    pool: <tenant>-<environment>
        +
        +

        Relevant documentation for applications:

        + +

        For NAIS

        +
          +
        • Enable Aiven for the tenant in nais-terraform-modules
        • +
        • +

          If the tenant wishes to use Kafka, enable Kafka in nais-terraform-modules

          +
        • +
        • +

          After terraform has created the necessary Aiven resources, enable relevant features in Fasit + (including required dependencies):

          +
            +
          • aiven-operator
          • +
          • mutilator
              +
            • Optionally configure OpenTelemetry endpoint
            • +
            +
          • +
          • aivenator
          • +
          +
        • +
        • +

          If Kafka is enabled, also enable these features:

          +
            +
          • kafka-canary
              +
            • In management environment
            • +
            +
          • +
          • kafkarator
          • +
          • aiven-alerts
          • +
          • kafka-canary-alert
          • +
          • kafka-lag-exporter
          • +
          +
        • +
        + + + + + + + + + + + + + + + + + + + + + + +
        +
        + + + + + +
        + +
        + + + +
        +
        +
        +
        + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/technical/tenant-setup/addons/azure-ad/index.html b/technical/tenant-setup/addons/azure-ad/index.html index 92fb8b9a..1eca3050 100644 --- a/technical/tenant-setup/addons/azure-ad/index.html +++ b/technical/tenant-setup/addons/azure-ad/index.html @@ -11,7 +11,7 @@ - + @@ -824,6 +824,8 @@ + + @@ -859,6 +861,27 @@ + + +
      43. + + + + + Aiven services and Kafka + + + + +
      44. + + + + + + + + @@ -1448,7 +1471,7 @@

        For NAIS - 2024-09-17 + 2024-09-17 @@ -1458,7 +1481,7 @@

        For NAIS - 2024-09-17 + 2024-09-17 @@ -1489,7 +1512,7 @@

        For NAIS - + diff --git a/technical/tenant-setup/addons/digdir/index.html b/technical/tenant-setup/addons/digdir/index.html index 0a2c0462..b3182bac 100644 --- a/technical/tenant-setup/addons/digdir/index.html +++ b/technical/tenant-setup/addons/digdir/index.html @@ -824,6 +824,8 @@ + + @@ -861,6 +863,27 @@ +
      45. + + + + + Aiven services and Kafka + + + + +
      46. + + + + + + + + + +
      47. @@ -1675,7 +1698,7 @@

        Google Secret Manager - 2024-09-17 + 2024-09-17 @@ -1685,7 +1708,7 @@

        Google Secret Manager - 2024-09-17 + 2024-09-17 diff --git a/technical/tenant-setup/addons/tokenx/index.html b/technical/tenant-setup/addons/tokenx/index.html index 44b1ae81..b14c8c5c 100644 --- a/technical/tenant-setup/addons/tokenx/index.html +++ b/technical/tenant-setup/addons/tokenx/index.html @@ -824,6 +824,8 @@ + + @@ -861,6 +863,27 @@ +
      48. + + + + + Aiven services and Kafka + + + + +
      49. + + + + + + + + + +
      50. @@ -1236,7 +1259,7 @@

        For NAIS operators - 2024-09-17 + 2024-09-17 @@ -1246,7 +1269,7 @@

        For NAIS operators - 2024-09-17 + 2024-09-17 diff --git a/technical/tenant-setup/addons/wonderwall/index.html b/technical/tenant-setup/addons/wonderwall/index.html index cfebe601..3e0c1fdd 100644 --- a/technical/tenant-setup/addons/wonderwall/index.html +++ b/technical/tenant-setup/addons/wonderwall/index.html @@ -824,6 +824,8 @@ + + @@ -861,6 +863,27 @@ +
      51. + + + + + Aiven services and Kafka + + + + +
      52. + + + + + + + + + +
      53. @@ -1323,7 +1346,7 @@

        Usage by ApplicationsFor NAIS

        Requirements

          -
        • Aiven must be enabled for the tenant.
        • +
        • Aiven must be enabled for the tenant.

        Enable the Wonderwall feature flag in naiserator

        Enable the Wonderwall feature in Fasit

        @@ -1356,7 +1379,7 @@

        Enable the Wonderwall feature in - 2024-09-17 + 2024-09-17 @@ -1366,7 +1389,7 @@

        Enable the Wonderwall feature in - 2024-09-17 + 2024-09-17 diff --git a/technical/tenant-setup/index.html b/technical/tenant-setup/index.html index 66bab945..5989e618 100644 --- a/technical/tenant-setup/index.html +++ b/technical/tenant-setup/index.html @@ -14,7 +14,7 @@ - + @@ -823,6 +823,8 @@ + + @@ -859,6 +861,27 @@ +
      54. + + + + + Aiven services and Kafka + + + + +
      55. + + + + + + + + + +
      56. @@ -1523,7 +1546,7 @@

        Github Actions secrets - 2024-09-17 + 2024-09-17 @@ -1533,7 +1556,7 @@

        Github Actions secrets - 2024-09-17 + 2024-09-17 @@ -1581,13 +1604,13 @@

        Github Actions secrets +