diff --git a/content/docs/administration/authentication/_index.md b/content/docs/administration/authentication/_index.md new file mode 100644 index 0000000..b3f4e25 --- /dev/null +++ b/content/docs/administration/authentication/_index.md @@ -0,0 +1,17 @@ +--- +title: "Authentication" +description: "" +summary: "" +date: 2024-08-14T13:50:47+03:00 +lastmod: 2024-08-14T13:50:47+03:00 +draft: false +weight: 210 +toc: true +sidebar: + collapsed: true +seo: + title: "" # custom title (optional) + description: "" # custom description (recommended) + canonical: "" # custom canonical URL (optional) + noindex: false # false (default) or true +--- diff --git a/content/docs/administration/authentication/basic-authentication.md b/content/docs/administration/authentication/basic-authentication.md new file mode 100644 index 0000000..c5cea91 --- /dev/null +++ b/content/docs/administration/authentication/basic-authentication.md @@ -0,0 +1,45 @@ +--- +title: "Basic Authentication" +description: "" +summary: "" +date: 2024-08-14T13:52:09+03:00 +lastmod: 2024-08-14T13:52:09+03:00 +draft: false +weight: 210 +toc: true +seo: + title: "" # custom title (optional) + description: "" # custom description (recommended) + canonical: "" # custom canonical URL (optional) + noindex: false # false (default) or true +--- + +The Control Plane REST API supports authentication with a username/password combination ([HTTP basic authentication](https://tools.ietf.org/html/rfc7617)). +This allows a user to use a fixed username/password combination which will never expire unless the password has changed. + +This is the simplest authentication mechanism, but has some security implications if the credentials are exposed to an attacker. To reduce security exposure, consider [Token Authentication]({{< ref "token-authentication.md" >}}) instead. + +## Examples + +The user name is supplied in the format `/` along with the password. + +{{< tabs "login" >}} +{{< tab "nuodb-cp" >}} + +```sh +nuodb-cp httpclient -u acme/dbuser -p "$PASS" ... +``` + +{{< /tab >}} +{{< tab "curl" >}} + +```sh +curl -u "acme/dbuser:$PASS" ... +``` + +{{< /tab >}} +{{< /tabs >}} + +### Bypassing Authentication on local requests + +If the REST server property `com.nuodb.controlplane.server.bypassLocalAuthentication` is set to `true`, then authentication and access control can be bypassed by issuing requests from a client on the same host as the REST server. diff --git a/content/docs/administration/authentication/token-authentication.md b/content/docs/administration/authentication/token-authentication.md new file mode 100644 index 0000000..e5b89d3 --- /dev/null +++ b/content/docs/administration/authentication/token-authentication.md @@ -0,0 +1,246 @@ +--- +title: "Token Authentication" +description: "" +summary: "" +date: 2024-08-14T13:52:09+03:00 +lastmod: 2024-08-14T13:52:09+03:00 +draft: false +weight: 215 +toc: true +seo: + title: "" # custom title (optional) + description: "" # custom description (recommended) + canonical: "" # custom canonical URL (optional) + noindex: false # false (default) or true +--- + +Token authentication enhances security by allowing access restrictions and an expiration to be specified when generating the token credentials. +If the token is exposed to an attacker, they would only have limited access to the resources and the token would become invalid after it expires. + +The token is secured by a secret key [configured](#securing--encrypting-the-token) on the REST server. + +A token can be created by authenticating with a valid `username/password` combination (Basic Authentication) or by authenticating with an existing token against the `/login` resource. +To minimize security risks, the request body should contain appropriate permissions and expiration times. +The server would respond with a `token` which can be used for subsequent calls to the REST services. + +For basic authentication requests, the requested permissions cannot exceed the authenticated user. +When logging in via a token, the expiration time and permissions cannot exceed the token used for authentication. + +## Token creation (authentication) + +A token is created and returned by sending a `POST /login` request and providing user credentials (i.e. username/password). + +Here is a simplified example of creating authentication token: + +```text +POST /login +Authorization: Basic YnN... +{...} + +HTTP/1.1 200 OK +{"token":"eyJ6a..."} +``` + +## Using the Token to access resources + +The value of the `token` attribute returned from the `/login` resource is passed into the `Authorization` header using the `Bearer` authorization scheme. + +For example: + +```text +GET /users/acme/orgadmin +Authorization: Bearer eyJ6a.... + +HTTP/1.1 OK +{"organization":"acme","name"......} +``` + +## Token Expiration + +The token expiration can be set with the `expiresIn` or `expiresAtTime` parameter. +If both are specified, `expiresAtTime` takes precedence. +If none are specified, it will set to the default of 2 hours. + +- `expiresIn` needs to be a number followed by either "s", "m" or "h" or a combination of them. It will create a token which will expire in the specified number of seconds, minutes or hours from now +- `expiresAtTime` specifies the time when the token should expire. It must be in ISO-8601 format, i.e. `YYYY-MM-DDTHH:MM:SSZ` + +{{< callout context="tip" title="Tip" icon="outline/brand-hipchat" >}} +The expiration timestamp should be chosen carefully. +If it is set too far into the future, an exposure of the token to an attacker could give them access to the resource for an extended period of time. +If the expiration is set too small, it would require the user to provide their credentials more often. +{{< /callout >}} + +For example, supply `expiresIn` to limit the token expiration: + +```text +POST /login +Authorization: Basic YWN..... +{"expiresIn":"3h"} + +HTTP/1.1 200 OK +{"token":"eyJ6a...."} +``` + +For example, use default token expiration settings: + +```text +POST /login +Authorization: Basic YWN..... +{"expiresAtTime":"2025-05-22T16:00:00Z"} + +HTTP/1.1 200 OK +{"token":"eyJ6a...."} +``` + +## Authorization (Access Rules) + +The user's access rules are controlled by [Access Rule Entries]({{< ref "user-access-rules.md" >}}). + +- if `limitAllow` rules are specified in the request, it will replace the existing "allow" rules for the user. If the user requests more permission than they (or the token during re-issue) has, the request will be rejected. +- if a `extraDeny` rule is specified, it will further restrict the user's permissions (it will be added to the user's deny rules, not replaced) +- The response fill return the resulting access levels for the user (a combination of the current user's (or token's) access rules with the requested ones) + +For example: + +```text +POST /login +Authorization: Basic YWN..... +{"limitAllow":["all:acme","read:corp"],"extraDeny":["delete:acme"]} + +HTTP/1.1 200 OK +{"token":"eyJ6a....", "accessRule":{"allow":["all:acme","raed:corp"], "deny":["delete:corp","delete:acme"]}} +``` + +## Re-Issuing a token + +Re-issuing a token with an existing token is permitted, but for security reasons restricted: + +- a re-issue of the token cannot exceed the existing expiration time +- specified access rules cannot exceed the existing access rules for the current token + +There are several scenarios where re-issuing a token is useful: + +- a token with a long expiration (stored in a very secure place like a security vault) can be created which can be used to re-issue a short lived token which could be shared with a temporary job. +- a token with higher permissions (access rules) can be re-issued with less access. For example a background process might need only read permissions. + +For example: + +```text +POST /login +Authorization: Bearer eyJ6..... +{"limitAllow":["all:acme","read:corp"],"extraDeny":["delete:acme"]} + +HTTP/1.1 200 OK +{"token":"abc...."} +``` + +## Token payload + +Once a user performs a login (via POST /login), the response will have a "token" attribute containing a [JWT token](https://datatracker.ietf.org/doc/html/rfc7519). For security reasons this token is encrypted. + +## Create and read a token + +If the `acme/orgadmin` user doesn't exist yet, [create]({{< ref "user-management.md" >}}#creating-users) it. + +{{< tabs "token" >}} +{{< tab "nuodb-cp" >}} + +```sh +nuodb-cp httpclient POST login --user acme/orgadmin --password secret \ + -d '{"extraDeny": ["write:*", "delete:*"]}' --jsonpath token --unquote +``` + +```json +{"token":"eyJ6aXAiOi...","accessRule": {"allow": ["all:acme"], "deny":"extraDeny":["write:*", "delete:*"]},"expiresAtTime":"2024-02-20T17:41:00Z"} +``` + +The returned token can be used by subsequent `nuodb-cp` commands by either setting the `NUODB_CP_TOKEN` environment variable or passing it to the `--token` argument. + +{{< /tab >}} +{{< tab "curl" >}} + +Set the environment variable `NUODB_CP_URL_BASE` to the REST service location, e.g. `http://server:8080` + +```sh +curl -X POST -H "Content-Type: application/json" $NUODB_CP_URL_BASE/login -u acme/orgadmin:passw0rd \ + -d '{"limitAllow":["all:acme"]}' +``` + +```json +{"token":"eyJ6aXAiOi...","accessRule": {"allow": ["all:acme"], "deny":"extraDeny":[]},"expiresAtTime":"2024-02-20T17:41:00Z"} +``` + +Authenticate the user with the token: + +```sh +curl $NUODB_CP_URL_BASE/users/acme -H "Authorization: Bearer eyJ6aXAiOi...." +``` + +```json +{"items":["orgadmin"]} +``` + +{{< /tab >}} +{{< /tabs >}} + +### Re-Issuing tokens with reduced permissions + +Especially for short running batch processes, it is often useful, to give a short lived token with minimal permissions to reduce a security exposure. +For example a parent process having a token with a long lived expiration date, can request a short lived token from the server and pass it to a child process to minimize security exposure. + +{{< tabs "login" >}} +{{< tab "nuodb-cp" >}} + +```sh +export NUODB_CP_TOKEN="$(nuodb-cp httpclient POST login \ + --token "eyJ6aXAi0i..." \ + -d '{"limitAllow": ["read:acme"]}' --jsonpath token --unquote)" +nuodb-cp database list acme +``` + +{{< /tab >}} +{{< tab "curl" >}} + +```sh +curl -X POST -H "Content-Type: application/json" $NUODB_CP_URL_BASE/login -H "Authorization: Bearer eyJ6aXAiOi..." \ + -d '{"limitAllow":["read:acme"]}' +``` + +```json +{"token":"abc..."} +``` + +{{< /tab >}} +{{< /tabs >}} + +## Appendix + +### Securing / Encrypting the token + +The token is secured by either a secret key or a cryptographically secure (and strong) password. +A Kubernetes secret will store this information and helm charts will create this key automatically if it doesn't exist. +Changing the key or password will invalidate all active tokens. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: nuodb-cp-runtime-config + namespace: nuodb +type: Opaque +data: + secretPassword: ..... +``` + +- secretKey - binary key. If not set, the `secretPassword` needs to be specified. +- secretPassword - password to convert into a key. Ignored if secretKey is specified. Please ensure it has sufficient strength. +- secretKeyAlgorithm - algorithm of the secret key. Defaults to `HmacSHA256` if it is not set. +- secretPasswordToKeyAlgorithm - algorithm to convert a password into a key. Defaults to `PBKDF2WithHmacSHA256` if it is not set. +- secretPasswordToKeyIterations - key generation iterations if `secretPassword` is set. Defaults to `65536` if set to a non-positive value. +- secretPasswordToKeyLength - key length if `secretPassword` is set. Defaults to `256` if set to a non-positive value. + +#### Create a secret password key in Kubernetes + +```sh +kubectl create secret generic nuodb-cp-runtime-config --from-literal secretPassword=changeIt +``` diff --git a/content/docs/administration/authentication/user-access-rules.md b/content/docs/administration/authentication/user-access-rules.md new file mode 100644 index 0000000..aee2d6c --- /dev/null +++ b/content/docs/administration/authentication/user-access-rules.md @@ -0,0 +1,138 @@ +--- +title: "User Access Control Rules" +description: "" +summary: "" +date: 2024-08-14T13:52:09+03:00 +lastmod: 2024-08-14T13:52:09+03:00 +draft: false +weight: 205 +toc: true +seo: + title: "" # custom title (optional) + description: "" # custom description (recommended) + canonical: "" # custom canonical URL (optional) + noindex: false # false (default) or true +--- + + +Access Rule Entries define what permissions a user has to one or multiple resources. +These permissions are defined during a [user create/update]({{< ref "user-management.md" >}}#creating-users) operation or optionally when creating an [authentication token]({{< ref "token-authentication.md" >}}) for a user. + +An access rule entry has the format `:[:]`. + +### Verb + +A _verb_ is one of the following and is associated with one or more HTTP methods. + +| verb | HTTP methods | +| -------- | ------------------------------- | +| `read` | `GET` | +| `write` | `PUT`, `PATCH` | +| `delete` | `DELETE` | +| `all` | `GET`, `PUT`, `PATCH`, `DELETE` | + +### Resource specifier + +A _resource specifier_ takes one of two forms: + +- If a resource specifier starts with `/`, then it is interpreted as an absolute resource path. + The first component of the path must be a resource type, such as `/projects`, `/databases/`, `/users`, and `/healthz`. +- Otherwise, it is interpreted as a _scope_, which has the format `//`, `/`, or ``. + A scope binds to a specific object in the hierarchy of DBaaS objects (_organizations_, _projects_, _databases_) and expands to the set of resource paths associated with that object. + For example, the scope `acme` expands to the resource paths `/projects/acme/*`, `/databases/acme/*`, and `/users/acme/*`, while `acme/messaging` expands to `/projects/acme/messaging/*` and `/databases/acme/messaging/*`. + +### SLA + +An optional third component of the access rule entry limits access to only projects that have matching SLA values and databases within those projects. +For example, `write:acme:dev` would grant write access to all projects within the `acme` organization with SLA `dev` and all of their databases. + +Only `allow` entries accept an SLA value. + +### Example: Full access + +To grant full access to all resources, the wildcard resource can be specified. + +```json +{ + "allow": "all:*" +} +``` + +{{< callout context="note" title="Note" icon="outline/info-circle" >}} +Either (or both) of the `allow` and `deny` fields in the access rule can be omitted or supplied with a string value, which expands to a single element array. +{{< /callout >}} + +### Example: Read and write access at different levels + +To grant read access at the organization level and write access at the project level, the following can be specified. + +```json +{ + "allow": ["read:acme", "write:acme/messaging"] +} +``` + +The rule above allows projects, databases, and users to be listed for the organization `acme` and allows the specific project `acme/messaging` to be written, as well as any database within `acme/messaging`. + +### Example: Access to specific resource paths + +Access can be granted to specific resource paths as follows: + +```json +{ + "allow": ["all:acme/messaging/demo", "all:/users/acme/dbuser"] +} +``` + +In the example above, the resource `/users/acme/dbuser` is specified to grant full access to that specific user. +This would allow a user to change its own password without having access to all resources at the organization level. + +### Example: Denying access to resource paths + +Access to specific resource paths can also be explicitly denied using the `deny` field. + +```json +{ + "allow": "all:acme", + "deny": "all:/users/*" +} +``` + +In the example above, full access is granted for all resources in the `acme` organization, except users. +Note that this is equivalent to the following access rule, assuming that the set of root resources expanded by an organization scope is `/projects`, `/databases`, and `/users`: + +```json +{ + "allow": ["all:/projects/acme/*", "all:/databases/acme/*"] +} +``` + +Although the two access rules are equivalent for the current version of the Control Plane REST API, they would behave differently if changes are made to the API. +The former would grant access to any organization-scoped resources that are added to the API, while the latter would not. +It is up to the administrator to decide which approach is best. + +### Example: Access to multiple organizations + +Even though each user belongs to a specific organization, it is possible to grant users access to multiple organizations, as shown below: + +```json +{ + "allow": ["all:acme", "read:notacme"] +} +``` + +{{< callout context="note" title="Note" icon="outline/info-circle" >}} +Adding access outside of a user's organization requires specifying the query parameter `allowCrossOrganizationAccess=true`, which is accepted by both `PUT` and `PATCH` requests on the user resource. +{{< /callout >}} + +### Example: Access constrained by SLA + +To grant access to only the projects and databases within a scope that have a particular SLA value, an SLA constraint can be specified: + +```json +{ + "allow": ["all:acme:dev", "read:acme:qa", "write:acme/messaging"] +} +``` + +In the example above, full access is granted to all projects and databases in `acme` that have SLA `dev`, read access is granted to projects and databases in `acme` that have SLA `qa`, and write access is granted to the specific project `acme/messaging`. diff --git a/content/docs/administration/user-management.md b/content/docs/administration/authentication/user-management.md similarity index 99% rename from content/docs/administration/user-management.md rename to content/docs/administration/authentication/user-management.md index e9fa38c..cdd042e 100644 --- a/content/docs/administration/user-management.md +++ b/content/docs/administration/authentication/user-management.md @@ -1,11 +1,11 @@ --- -title: "User Management and Access Control" +title: "User Management" description: "" summary: "" date: 2024-08-14T13:52:09+03:00 lastmod: 2024-08-14T13:52:09+03:00 draft: false -weight: 210 +weight: 200 toc: true seo: title: "" # custom title (optional) diff --git a/content/docs/administration/offerings/_index.md b/content/docs/administration/offerings/_index.md new file mode 100644 index 0000000..c1e15e8 --- /dev/null +++ b/content/docs/administration/offerings/_index.md @@ -0,0 +1,17 @@ +--- +title: "Offerings" +description: "" +summary: "" +date: 2024-08-14T13:50:47+03:00 +lastmod: 2024-08-14T13:50:47+03:00 +draft: false +weight: 300 +toc: true +sidebar: + collapsed: true +seo: + title: "" # custom title (optional) + description: "" # custom description (recommended) + canonical: "" # custom canonical URL (optional) + noindex: false # false (default) or true +--- diff --git a/content/docs/administration/offerings/service-tiers.md b/content/docs/administration/offerings/service-tiers.md new file mode 100644 index 0000000..1d506f7 --- /dev/null +++ b/content/docs/administration/offerings/service-tiers.md @@ -0,0 +1,107 @@ +--- +title: "Service Tiers" +description: "" +summary: "" +date: 2024-08-14T13:52:09+03:00 +lastmod: 2024-08-14T13:52:09+03:00 +draft: false +weight: 210 +toc: true +seo: + title: "" # custom title (optional) + description: "" # custom description (recommended) + canonical: "" # custom canonical URL (optional) + noindex: false # false (default) or true +--- + +The NuoDB DBaaS databases are deployed using the production-ready [NuoDB Helm Charts](https://github.com/nuodb/nuodb-helm-charts) which allows fine-tuning for all aspects of database configuration. +Parameterizing the product using Helm values provides a lot of flexibility but requires in-depth knowledge of the Helm chart and the target deployment environment. +This is why with NuoDB DBaaS only a subset of configurable parameters are exposed in a controlled way. +All other parameters are defaulted by using high-level pre-configured database specifications called _service tiers_. + +## Database Configuration + +The NuoDB service tier is a composition of one or more Helm features. +Each feature can be referenced by multiple service tiers and contains raw Helm values that enable the feature in the Helm charts. +Both tiers and features are stored as Kubernetes [custom resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) and managed through the Kubernetes API server using standard deployment tools. + +{{< callout context="note" title="Note" icon="outline/info-circle" >}} +DBaaS users themselves don’t have access to the definitions of the Helm features as they serve as an abstraction to Helm configuration. +The DBaaS administration team can define new or modify existing features and service tiers. +{{< /callout >}} + +## Example: Composition + +To illustrate the above, let’s have a closer look at some examples. +The sample _n1.small_ service tier references four Helm features defining different database configuration aspects. + +```yaml +apiVersion: cp.nuodb.com/v1beta1 +kind: ServiceTier +metadata: + name: n1.small + annotations: + description: |- + A general-purpose NuoDB service resilient to failures with 1 vCPU, 2G memory, \ + 20G storage and SSD disks. The database will be started with 2 Storage Managers \ + and 3 Transaction Engines. +spec: + features: + - name: small-resources + - name: small-disk + - name: io1-disk + - name: n1-replicas +``` + +The sample _n1-replicas_ feature configures the initial replicas for admin processes (AP), Transaction Engines (TE) and Storage Managers (SM) for NuoDB database. + +```yaml +apiVersion: cp.nuodb.com/v1beta1 +kind: HelmFeature +metadata: + name: n1-replicas +spec: + values: + admin: + replicas: 3 + database: + sm: + hotCopy: + enablePod: false + noHotCopy: + replicas: 2 + te: + replicas: 3 +``` + +The below diagram shows how several Helm features (in green) are re-used and composed into different service tiers (in blue). + +{{< picture src="tier-composition.jpg" alt="Service tier and Helm features composition" >}} + +The feature composition is controlled by the NuoDB product version or NuoDB Helm Charts version. +In the diagram above the _thp-affinity_ feature is configured as optional by declaring `chartCompatibility` and `productCompatibility` properties which use semantic version constraints. + +## Usage + +Once a service tier is created, any database instance can reference it as shown below. + +```yaml +apiVersion: cp.nuodb.com/v1beta1 +kind: Database +metadata: + name: acme-messaging-demo +spec: + version: "6.0" + type: + tierRef: + name: n1.small + sla: qa + dbName: demo + domainRef: + name: acme-messaging + passwordRef: + kind: Secret + name: acme-messaging-demo-credentials +``` + +Having such flexibility for managing a discrete number of supported and exposed database configurations, empowers the DBaaS deployment, operations, and product management teams to support different deployment environments, roll out hot-fixes and enforce the desired DBaaS pricing model. diff --git a/content/docs/administration/offerings/tier-composition.jpg b/content/docs/administration/offerings/tier-composition.jpg new file mode 100644 index 0000000..9d355c0 Binary files /dev/null and b/content/docs/administration/offerings/tier-composition.jpg differ diff --git a/content/docs/administration/troubleshooting/_index.md b/content/docs/administration/troubleshooting/_index.md new file mode 100644 index 0000000..3311883 --- /dev/null +++ b/content/docs/administration/troubleshooting/_index.md @@ -0,0 +1,17 @@ +--- +title: "Troubleshooting" +description: "" +summary: "" +date: 2024-08-14T13:50:47+03:00 +lastmod: 2024-08-14T13:50:47+03:00 +draft: false +weight: 900 +toc: true +sidebar: + collapsed: true +seo: + title: "" # custom title (optional) + description: "" # custom description (recommended) + canonical: "" # custom canonical URL (optional) + noindex: false # false (default) or true +--- diff --git a/content/docs/administration/troubleshooting/undo-tier-deletion.md b/content/docs/administration/troubleshooting/undo-tier-deletion.md new file mode 100644 index 0000000..4a8292b --- /dev/null +++ b/content/docs/administration/troubleshooting/undo-tier-deletion.md @@ -0,0 +1,131 @@ +--- +title: "Undo Tier Configuration Deletion" +description: "" +summary: "" +date: 2024-08-14T13:52:09+03:00 +lastmod: 2024-08-14T13:52:09+03:00 +draft: false +weight: 905 +toc: true +seo: + title: "" # custom title (optional) + description: "" # custom description (recommended) + canonical: "" # custom canonical URL (optional) + noindex: false # false (default) or true +--- + +This guide describes how to re-create deleted NuoDB Control Plane(CP) service tier configuration. + +## Service Tier and Helm Feature Deletion + +The NuoDB CP creates and uses kubernetes custom resource definitions(CRDs) to describe and set different service tiers and NuoDB helm chart values for domain and database resources. The NuoDB operator sets [Finalizers](https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/) on these resources to prevent deletion of a tier or feature while they are actively used by running domains and databases. + +If a service tier or a helm feature is unintentionally deleted, by automation or human error, it will leave the resource in a deleted state, for example: + +```json +{ + "level":"error", + "ts":"2023-02-10T16:55:10.098Z", + "logger":"controller.servicetier", + "msg":"unable to delete service tier", + "reconciler group":"cp.nuodb.com", + "reconciler kind":"ServiceTier", + "name":"n0.small", + "namespace":"nuodb-cp-system", + "error":"resources that have reference to service tier nuodb-cp-system/n0.small: [domain/nuodb-cp-system/acme-messaging database/nuodb-cp-system/acme-messaging-demo]" +} +``` + +While domain and database objects continue to operate as normal, future updates will not be possible until the deletion is reversed. + +### Service Tier + +To reverse the deletion of a service tier, first list all service tiers that are in a deleted state: + +```sh +kubectl get tier -o jsonpath='{.items[?(@.metadata.deletionTimestamp)].metadata.name}' +``` + +This will return an output similar to: + +```text +n0.small +... +``` + +A change in a service tier is directly propagated to all databases. +Both the domain and the database controllers will perform validation of the resource before the actual reconciliation. + +{{< callout context="note" title="Note" icon="outline/info-circle" >}} +Once a tier resource is force deleted (by manually removing its finalizers), all domains and databases that reference it will transition its `Ready` condition to False with reason `ValidationFailed`. +{{< /callout >}} + +After the tier resource is re-created, the databases will be reported ready almost instantly. +No database Pod restarts will be performed and the service won't be interrupted during this time. + +Export the selected service tier as YAML: + +```sh +kubectl get tier n0.small -o yaml | sed -e '/deletionTimestamp/d' -e '/deletionGracePeriodSeconds/d' > tier-backup.yaml +``` + +Re-create the service tier: + +```sh +kubectl patch tier n0.small -p '{"metadata":{"finalizers":null}}' --type=merge +kubectl create -f tier-backup.yaml +``` + +### Helm Feature + +To reverse the deletion of a helm feature, first list all helm features that are in a deleted state: + +```sh +kubectl get feature -o jsonpath='{.items[?(@.metadata.deletionTimestamp)].metadata.name}' +``` + +This will return an output similar to: + +```text +small-resources +... + +``` + +There is a level of indirection as the features are referenced in tiers. +A database reconciliation will be triggered only if the `cp.nuodb.com/features-hash` annotation value changes. +If a referenced feature is force removed (by manually removing it's finalizers), the hash calculation will fail, preventing event propagation to all databases. + +Example error for hash calculation: + +```json +{ + "level":"error", + "ts":"2023-03-06T08:43:44.846Z", + "msg":"unable to find referenced features", + "controller":"servicetier", + "controllerGroup":"cp.nuodb.com", + "controllerKind":"ServiceTier", + "ServiceTier":{ + "name":"n1.small", + "namespace":"nuodb-cp-system" + }, + "namespace":"nuodb-cp-system", + "name":"n1.small", + "reconcileID":"5d6350be-e9c9-450a-b5cc-67b92816378f", + "error":"HelmFeature.cp.nuodb.com \"small-resources\" not found", + "errorCauses":[{"error":"HelmFeature.cp.nuodb.com \"small-resources\" not found"}]} +``` + +Export the selected service tier as YAML: + +```sh +kubectl get feature small-resources -o yaml | sed -e '/deletionTimestamp/d' -e '/deletionGracePeriodSeconds/d' > feature-backup.yaml +``` + +Re-create the service tier: + +```sh +kubectl patch feature small-resources -p '{"metadata":{"finalizers":null}}' --type=merge +kubectl create -f feature-backup.yaml +``` diff --git a/content/docs/getting-started/connect-dbaas.md b/content/docs/getting-started/connect-dbaas.md index 4a71bde..bc08097 100644 --- a/content/docs/getting-started/connect-dbaas.md +++ b/content/docs/getting-started/connect-dbaas.md @@ -49,7 +49,7 @@ export NUODB_CP_PASSWORD="$(kubectl get secret dbaas-user-system-admin -n nuodb- {{< callout context="note" title="Note" icon="outline/info-circle" >}} The *system/admin* is the first cluster administrator user created during installation. It is recommended to create less privileged users after installation. -For more information, see [User Management and Access Control]({{< ref "../administration/user-management.md" >}}). +For more information, see [User Management and Access Control]({{< ref "../administration/authentication/user-management.md" >}}). {{< /callout >}} If the Nginx TLS certificate is not signed by a public CA, configure `nuodb-cp` to trust it.