diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml new file mode 100644 index 00000000..3fa07ca8 --- /dev/null +++ b/.github/workflows/linting.yaml @@ -0,0 +1,18 @@ +name: Markdown Linter +on: [pull_request, push] +permissions: + contents: read +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout markdown + uses: actions/checkout@v4.2.0 + - name: Lint markdown + uses: DavidAnson/markdownlint-cli2-action@v17 + continue-on-error: true + with: + config: '.markdownlint.yml' + globs: | + docs/*.md + !examples/*.md \ No newline at end of file diff --git a/.markdownlint.yml b/.markdownlint.yml new file mode 100644 index 00000000..188dd322 --- /dev/null +++ b/.markdownlint.yml @@ -0,0 +1,140 @@ +default: false + +# MD001/heading-increment : Heading levels should only increment by one level at a time : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md001.md +MD001: true + +# MD003/heading-style : Heading style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md003.md +MD003: + style: "consistent" + +# MD004/ul-style : Unordered list style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md004.md +MD004: + style: "consistent" + +# MD005/list-indent : Inconsistent indentation for list items at the same level : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md005.md +MD005: true + +# MD007/ul-indent : Unordered list indentation : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md007.md +MD007: + indent: 4 + +# MD009/no-trailing-spaces : Trailing spaces : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md009.md +MD009: true + +# MD010/no-hard-tabs : Hard tabs : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md010.md +MD010: true + +# MD011/no-reversed-links : Reversed link syntax : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md011.md +MD011: true + +# MD012/no-multiple-blanks : Multiple consecutive blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md012.md +MD012: true + +# MD014/commands-show-output : Dollar signs used before commands without showing output : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md014.md +MD014: true + +# MD018/no-missing-space-atx : No space after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md018.md +MD018: true + +# MD019/no-multiple-space-atx : Multiple spaces after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md019.md +MD019: true + +# MD020/no-missing-space-closed-atx : No space inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md020.md +MD020: true + +# MD021/no-multiple-space-closed-atx : Multiple spaces inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md021.md +MD021: true + +# MD022/blanks-around-headings : Headings should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md022.md +MD022: true + +# MD023/heading-start-left : Headings must start at the beginning of the line : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md023.md +MD023: true + +# MD024/no-duplicate-heading : Multiple headings with the same content : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md024.md +MD024: + siblings_only: true + +# MD025/single-title/single-h1 : Multiple top-level headings in the same document : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md025.md +MD025: true + +# MD026/no-trailing-punctuation : Trailing punctuation in heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md026.md +MD026: true + +# MD027/no-multiple-space-blockquote : Multiple spaces after blockquote symbol : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md027.md +MD027: true + +# MD028/no-blanks-blockquote : Blank line inside blockquote : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md028.md +MD028: true + +# MD029/ol-prefix : Ordered list item prefix : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md029.md +MD029: + style: "ordered" + +# MD030/list-marker-space : Spaces after list markers : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md030.md +MD030: + ul_single: 1 + ol_single: 1 + ul_multi: 3 + ol_multi: 2 + +# MD031/blanks-around-fences : Fenced code blocks should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md031.md +MD031: true + +# MD032/blanks-around-lists : Lists should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md032.md +MD032: true + +# MD034/no-bare-urls : Bare URL used : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md034.md +MD034: true + +# MD035/hr-style : Horizontal rule style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md035.md +MD035: true + +# MD036/no-emphasis-as-heading : Emphasis used instead of a heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md036.md +MD036: true + +# MD037/no-space-in-emphasis : Spaces inside emphasis markers : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md037.md +MD037: true + +# MD038/no-space-in-code : Spaces inside code span elements : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md038.md +MD038: true + +# MD039/no-space-in-links : Spaces inside link text : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md039.md +MD039: true + +# MD042/no-empty-links : No empty links : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md042.md +MD042: true + +# MD045/no-alt-text : Images should have alternate text (alt text) : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md045.md +MD045: true + +# MD046/code-block-style : Code block style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md046.md +MD046: + style: "fenced" + +# MD047/single-trailing-newline : Files should end with a single newline character : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md047.md +MD047: true + +# MD048/code-fence-style : Code fence style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md048.md +MD048: + style: "backtick" + +# MD049/emphasis-style : Emphasis style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md049.md +MD049: + style: "asterisk" + +# MD050/strong-style : Strong style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md050.md +MD050: + style: "consistent" + +# MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md051.md +MD051: true + +# MD053/link-image-reference-definitions : Link and image reference definitions should be needed : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md053.md +MD053: true + +# MD054/link-image-style : Link and image style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md054.md +MD054: true + +# MD056/table-column-count : Table column count : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md056.md +MD056: true \ No newline at end of file diff --git a/docs/blogs.md b/docs/blogs.md index 01334773..9fd064d6 100644 --- a/docs/blogs.md +++ b/docs/blogs.md @@ -11,5 +11,4 @@ | 2021-08-23 | [Shepherding your Cloud Native “cattle” with Tornjak](https://medium.com/universal-workload-identity/shepherding-your-cloud-native-cattle-with-tornjak-eb0b9a7c96bc) | Introduction to Tornjak | | 2021-08-26 | [Open source workload identity management could help secure hybrid clouds](https://research.ibm.com/blog/tornjak-project-cncf) | IBM donates Tornjak to CNCF | - [Tornjak Channel on Medium](https://medium.com/universal-workload-identity) diff --git a/docs/config-tornjak-server.md b/docs/config-tornjak-server.md index 0ff338c3..f5b2bea7 100644 --- a/docs/config-tornjak-server.md +++ b/docs/config-tornjak-server.md @@ -3,6 +3,7 @@ This document is a reference for the Tornjak server, and it follows the [SPIRE server config](https://github.com/spiffe/spire/blob/main/doc/spire_server.md). It includes information about plugin types, built-in plugins, the server configuration file, plugin configuration, and command line options for `tornjak-agent` commands. ## Contents + - [Command line options](#command-line-options) - [The Tornjak Config](#the-tornjak-config) - [General Tornjak Server Configs](#general-tornjak-server-configs) @@ -20,20 +21,22 @@ The following flags are available for all tornjak-agent commands: | `--tornjak-config` | Config file path for Tornjak agent | | true | | `--expandEnv` | If flag included, expand environment variables in Tornjak config | false | false | -Note these flags are passed in directly through the Tornjak container. +Note these flags are passed in directly through the Tornjak container. ### `tornjak-backend serverinfo` -Prints the SPIRE config and Tornjak config given. + +Prints the SPIRE config and Tornjak config given. ### `tornjak-backend http` -Runs the tornjak server. +Runs the tornjak server. ## The Tornjak Config -The Tornjak config that is passed in must follow a specific format. Examples of this format can be found [below](#sample-configuration-files). In general, it is split into the `server` section with [general Tornjak server configs](#general-tornjak-server-configs), and the `plugins` section. +The Tornjak config that is passed in must follow a specific format. Examples of this format can be found [below](#sample-configuration-files). In general, it is split into the `server` section with [general Tornjak server configs](#general-tornjak-server-configs), and the `plugins` section. ## General Tornjak Server Configs + The server config will contain information for the two potential connections: HTTP and HTTPS. HTTPS can be configured to follow TLS or mTLS protocol. See below for sample configuration: ```hcl @@ -42,7 +45,7 @@ server { spire_socket_path = "unix:///tmp/spire-server/private/api.sock" # socket to communicate with SPIRE server http { # required block - port = 10000 # if HTTP enabled, opens HTTP listen port at container port 10000 + port = 10000 # if HTTP enabled, opens HTTP listen port at container port 10000 } https { # optional, recommended block @@ -55,11 +58,11 @@ server { } ``` -We have two connection types that are opened by the server simultaneously: HTTP and HTTPS. HTTP is always operational. The optional HTTPS connection is recommended for production use case. When HTTPS is configured, the HTTP connection will redirect to the HTTPS (port and service). +We have two connection types that are opened by the server simultaneously: HTTP and HTTPS. HTTP is always operational. The optional HTTPS connection is recommended for production use case. When HTTPS is configured, the HTTP connection will redirect to the HTTPS (port and service). -Under the HTTPS block, the fields `port`, `cert`, and `key` are required to enable TLS connection. To enable the mutual TLS (mTLS), you must additionally include the `client_ca` field, so the verification can be done bi-directionally. +Under the HTTPS block, the fields `port`, `cert`, and `key` are required to enable TLS connection. To enable the mutual TLS (mTLS), you must additionally include the `client_ca` field, so the verification can be done bi-directionally. -For examples on enabling TLS and mTLS connections, please see [our TLS and mTLS documentation](../sample-keys/README.md). +For examples on enabling TLS and mTLS connections, please see [our TLS and mTLS documentation](../sample-keys/README.md). ## About Tornjak plugins @@ -79,7 +82,7 @@ Tornjak supports several different plugin types, each representing a different f | Type | Name | Description | | ---- | ---- | ----------- | -| DataStore | [sql]() | Default SQL storage for Tornjak metadata | +| DataStore | SQL | Default SQL storage for Tornjak metadata | | Authenticator | [keycloak](/docs/plugin_server_authentication_keycloak.md) | Perform OIDC Discovery and extract roles from `realmAccess.roles` field | | Authorizer | [RBAC](/docs/plugin_server_authorization_rbac.md) | Check api permission based on user role and defined authorization logic | @@ -111,6 +114,5 @@ We have an extended configuration file with comments on each section found [here ## Further reading -* [Tornjak Agent Architecture Overview](https://github.com/spiffe/tornjak/blob/main/docs/tornjak-agent.md) -* [Tornjak API Documentation](https://github.com/spiffe/tornjak/blob/main/docs/tornjak-ui-api-documentation.md) - +- [Tornjak Agent Architecture Overview](https://github.com/spiffe/tornjak/blob/main/docs/tornjak-agent.md) +- [Tornjak API Documentation](https://github.com/spiffe/tornjak/blob/main/docs/tornjak-ui-api-documentation.md) diff --git a/docs/newEntry-json-format.md b/docs/newEntry-json-format.md index 31ebfc2e..772160d6 100644 --- a/docs/newEntry-json-format.md +++ b/docs/newEntry-json-format.md @@ -1,3 +1,5 @@ +## JSON Format for New Entry + ```json { "entries": [ @@ -38,4 +40,4 @@ } ] } -``` \ No newline at end of file +``` diff --git a/docs/plan.md b/docs/plan.md index 3d348b39..6eacd8a0 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -1,17 +1,18 @@ # Tornjak Plan -Due to there being several components that need to be built as well as dependencies on continuing effort, the work can be broken down into milestones. +Due to there being several components that need to be built as well as dependencies on continuing effort, the work can be broken down into milestones. The nature of the design specification of milestones is based on two main ideas: + 1. The scope of capabilities/goals that can be achieved 2. The dependencies required based on on-going and planned work in the community - ## Milestones Here are a set of milestones. It is defined in an order but does not have to strictly follow it apart from Milestones A and B to lay the foundations of other milestones. List of milestones + - [Milestone A: Global Visibility](#milestone-a-global-visibility) - [Milestone B: Global Visibility + Authentication](#milestone-b-global-visibility--authentication) - [Milestone C: Policy management](#milestone-c-policy-management) @@ -28,20 +29,18 @@ Very simple global visibility and management of SPIRE APIs with simple authentic Feature dependencies: None -- Agent - - APIS: Implement only SPIRE server APIs - - No Authentication - - No Authorization -- Manager - - Global Visibility - - Add tornjak agent (backend call instead, not addition to UI) - - SPIRE API actions on servers - - No server info + custom tornjak APIs - - No Identity policy management - - No Auditability of idetntites - - No Management of SPIRE identity Configurations - - +- Agent + - APIS: Implement only SPIRE server APIs + - No Authentication + - No Authorization +- Manager + - Global Visibility + - Add tornjak agent (backend call instead, not addition to UI) + - SPIRE API actions on servers + - No server info + custom tornjak APIs + - No Identity policy management + - No Auditability of idetntites + - No Management of SPIRE identity Configurations ### Milestone B: Global Visibility + Authentication @@ -52,10 +51,10 @@ Add ability to obtain server info and some custom tornjak APIs with simple authe Feature dependencies: None In addition to above: -- Agent - - APIS: Implement some custom tornjak APIs - - Authentication via simple certificate auth from configured root CA on agent +- Agent + - APIS: Implement some custom tornjak APIs + - Authentication via simple certificate auth from configured root CA on agent ### Milestone C: Policy management @@ -67,17 +66,18 @@ the workload registrar usecase with a stricter threat model enforced by policy. Feature dependencies: [Authorization and policy management (Issue #1975)](https://github.com/spiffe/spire/issues/1975) In addition to above: -- Agent - - Authorization through SPIRE configuration -- Manager - - Provide an interface to the policy engines used by the SPIRE deployments - - Actions - - Add policy engine - - Provide address - - Choose authentication method - User or Certificate [pending auth issue #TBD] - - CRUD on policies - - No Visibility and consumability of policies - - No Provide templates for more complex policies to be created + +- Agent + - Authorization through SPIRE configuration +- Manager + - Provide an interface to the policy engines used by the SPIRE deployments + - Actions + - Add policy engine + - Provide address + - Choose authentication method - User or Certificate [pending auth issue #TBD] + - CRUD on policies + - No Visibility and consumability of policies + - No Provide templates for more complex policies to be created ### Milestone D: Improve Policy definitions and UX @@ -89,9 +89,10 @@ more sophisticated identity policy. Feature dependencies: [Authorization and policy management (Issue #1975)](https://github.com/spiffe/spire/issues/1975) In addition to above: -- Manager - - Visibility and consumability of policies - - Provide templates for more complex policies to be created + +- Manager + - Visibility and consumability of policies + - Provide templates for more complex policies to be created ### Milestone E: Auditability @@ -99,8 +100,8 @@ In addition to above: Feature Dependencies: Advanced Logging entries and infrastructure for SPIRE (Issue TBD) -- Manager - - Auditability of Identities and use for operations/forensics +- Manager + - Auditability of Identities and use for operations/forensics ### Milestone F: Advanced Authentication @@ -109,9 +110,9 @@ Feature Dependencies: Advanced Logging entries and infrastructure for SPIRE (Iss Feature dependencies: [More Admin Authentication mechanisms for SPIRE server (Issue #2099)](https://github.com/spiffe/spire/issues/2099) Other missing features: -- Agent - - More sophisticated authentication mechanisms + move authentication mechanisms to use SPIRE native (Dependencies: More authentication options for SPIRE) +- Agent + - More sophisticated authentication mechanisms + move authentication mechanisms to use SPIRE native (Dependencies: More authentication options for SPIRE) ### Milestone G: Enhancing SPIRE API @@ -120,5 +121,6 @@ Other missing features: Feature dependencies: Augment SPIRE API (Issue TBD) Other missing features: -- Manager - - Management of SPIRE Identity configurations (Dependencies: SPIRE API boundary decisions) + +- Manager + - Management of SPIRE Identity configurations (Dependencies: SPIRE API boundary decisions) diff --git a/docs/plugin_server_authentication_keycloak.md b/docs/plugin_server_authentication_keycloak.md index c81900db..529cf67e 100644 --- a/docs/plugin_server_authentication_keycloak.md +++ b/docs/plugin_server_authentication_keycloak.md @@ -1,12 +1,12 @@ # Server plugin: Authentication "Keycloak" -Please see our documentation on the [authorization feature](./user-management.md) for more complete details. +Please see our documentation on the [authorization feature](./user-management.md) for more complete details. Note that simply enabling this feature will NOT enable authorization. In order to apply authorization logic to user details, one must also enable an Authorization plugin. Any output from this layer, including authentication errors, are to be interpreted by an Authorization layer. The configuration has the following key-value pairs: -| Key | Description | Required | +| Key | Description | Required | | ----------- | ----------------------------------------------------------------------- | ------------------- | | issuer | Issuer URL for OIDC Discovery with external IAM System | True | | audience | Expected audience value in received JWT tokens | False (Recommended) | @@ -22,11 +22,11 @@ A sample configuration file for syntactic referense is below: } ``` -NOTE: If audience field is missing or empty, the server will log a warning and NOT perform an audience check. -It is highly recommended `audience` is populated to ensure only tokens meant for the Tornjak Backend are accepted. +NOTE: If audience field is missing or empty, the server will log a warning and NOT perform an audience check. +It is highly recommended `audience` is populated to ensure only tokens meant for the Tornjak Backend are accepted. ## User Info extracted This plugin assumes roles are available in `realm_access.roles` in the JWT and passes this list as user.roles. -These mapped values are passed to the authorization layer. +These mapped values are passed to the authorization layer. diff --git a/docs/plugin_server_authorization_rbac.md b/docs/plugin_server_authorization_rbac.md index 781e7ef9..446c754d 100644 --- a/docs/plugin_server_authorization_rbac.md +++ b/docs/plugin_server_authorization_rbac.md @@ -1,8 +1,8 @@ # Server plugin: Authorization "RBAC" -Please see our documentation on the [authorization feature](./user-management.md) for more complete details. +Please see our documentation on the [authorization feature](./user-management.md) for more complete details. -This configuration has the following inputs: +This configuration has the following inputs: | Key | Description | Required | | --- | ----------- | -------- | @@ -10,7 +10,7 @@ This configuration has the following inputs: | `role "" {desc = ""}` | `` is the name of a role that can be allowed access; `` is a short description | no | | `API "" {allowed_roles = ["", ...]}` | `` is the name of the API that will allow access to roles listed such as `` | no | -There can (and likely will be) multiple `role` and `API` blocks. If there are no role blocks, no API will be allowed any access. If there is a missing API block, no access will be granted for that API. +There can (and likely will be) multiple `role` and `API` blocks. If there are no role blocks, no API will be allowed any access. If there is a missing API block, no access will be granted for that API. A sample configuration file for syntactic referense is below: @@ -44,13 +44,13 @@ Authorizer "RBAC" { } ``` -NOTE: If this feature is enabled without an authentication layer, it will render all calls uncallable. +NOTE: If this feature is enabled without an authentication layer, it will render all calls uncallable. -The above specification assumes roles `admin` and `viewer` are passed by the authentication layer. In this example, the following apply: +The above specification assumes roles `admin` and `viewer` are passed by the authentication layer. In this example, the following apply: 1. If user has `admin` role, can perform any call 2. If user has `viewer` role, can perform all read-only calls (See lists below) -3. If user is authenticated with no role, can perform only `/` Tornjak home call. +3. If user is authenticated with no role, can perform only `/` Tornjak home call. ## Valid inputs @@ -61,10 +61,8 @@ There are a couple failure cases in which the plugin will fail to initialize and ## The empty string role "" -If there is a role listed with name `""`, this enables some APIs to allow all users where the authentication layer does not return error. In the above example, only the `/` API has this behavior. +If there is a role listed with name `""`, this enables some APIs to allow all users where the authentication layer does not return error. In the above example, only the `/` API has this behavior. ## Additional behavior specification -If there is a role that is not included as an `allowed_role` in any API block, a user will not be granted access to any API based on that role. - - +If there is a role that is not included as an `allowed_role` in any API block, a user will not be granted access to any API based on that role. diff --git a/docs/plugin_server_datastore_sql.md b/docs/plugin_server_datastore_sql.md index c4279fbb..a36b4d12 100644 --- a/docs/plugin_server_datastore_sql.md +++ b/docs/plugin_server_datastore_sql.md @@ -1,10 +1,10 @@ # Server plugin: Datastore "SQL" -Note the Datastore is a required plugin, and currently, as the SQL datastore is the only supported instance of the datastore plugin, there must be a section configuring this upon Tornjak backend startup. +Note the Datastore is a required plugin, and currently, as the SQL datastore is the only supported instance of the datastore plugin, there must be a section configuring this upon Tornjak backend startup. The configuration has the following key-value pairs: -| Key | Description | Required | +| Key | Description | Required | | ----------- | ---------------------------- | ------------------- | | drivername | Driver for SQL database | True | | filename | Location of database | True | @@ -19,4 +19,3 @@ A sample configuration file for syntactic reference is below: } } ``` - diff --git a/docs/tornjak-agent.md b/docs/tornjak-agent.md index ac2f114f..82d6a6f6 100644 --- a/docs/tornjak-agent.md +++ b/docs/tornjak-agent.md @@ -4,9 +4,10 @@ The components of tornjak on the SPIRE server should ideally be minimal. It should leverage the APIs of the SPIRE server as well as all the controls based around the SPIRE server, this leads to enforcement point being as close to the action as well as not having to have additional management throughout the stack. However, in order to fulfill some of the capabilities that are needed today and current state of features being developed, the component will take up a bigger role, this includes processing of outputs from the SPIRE api as well as storing additional metadata to provide additional functionality. -As certain new features are built out in SPIRE, these responsibility can then be transfered to use SPIRE native mechanisms. In addition, if certain additional APIs will have a corresponding API in the future, then the capabilities will move to using the SPIRE APIs. +As certain new features are built out in SPIRE, these responsibility can then be transfered to use SPIRE native mechanisms. In addition, if certain additional APIs will have a corresponding API in the future, then the capabilities will move to using the SPIRE APIs. ## Tornjak SPIRE Server Agent + - Provides “proxy” to SPIRE API services - Provides additional APIs that are useful to management - Ideally all useful information will be part of the SPIRE API, calling through Tornjak SPIRE backend, but because additional information is required and components are still not yet in place to enable direct pass through for authentication (issue #TBD) and authorization yet (issue #1975), some functionality is implemented as part of the Tornjak agent server with its own data storage. @@ -16,22 +17,25 @@ services, the architecture would look a bit more like this: ![tornjak-agent](rsrc/agent-extended.png) -### APIs: -- SPIRE specific - - /api/spire/agent/* - - /api/spire/entry/* - - etc. -- Example additional APIs - - /api/tornjak/* - - e.g. - - /api/tornjak/getserverinfo - - /api/tornjak/getlogs +### APIs + +- SPIRE specific + - /api/spire/agent/* + - /api/spire/entry/* - etc. +- Example additional APIs + - /api/tornjak/* + - e.g. + - /api/tornjak/getserverinfo + - /api/tornjak/getlogs + - etc. -### Authentication: -- Ideally, authentication should be handled through SPIRE server, today, this is done via the socket or via the "Admin" flag for a SPIFFE ID within the trust domain. There are conversations about this (#2099)[https://github.com/spiffe/spire/issues/2099] to enable SPIFFE IDs outside the trust domain of the SPIRE server or through other authentication mechanisms to administer the SPIRE server. This is to address the bootstrapping problem of administration of a SPIRE server. +### Authentication + +- Ideally, authentication should be handled through SPIRE server, today, this is done via the socket or via the "Admin" flag for a SPIFFE ID within the trust domain. There are conversations about this [#2099](https://github.com/spiffe/spire/issues/2099) to enable SPIFFE IDs outside the trust domain of the SPIRE server or through other authentication mechanisms to administer the SPIRE server. This is to address the bootstrapping problem of administration of a SPIRE server. - In the meantime, the Tornjak agent will use the socket to authenticate with the SPIRE server. This means that additional authentication needs to be done to authenticate the caller (management plane) to the agent. For this, we will implement standard client authentication mechanisms configured on the agent. This will mirror the configuration of our ideal state with a workaround for authentication to be done. ### Authorization + - Ideally, authentication should be handled through SPIRE server mechanisms, with the feature from [#1975](https://github.com/spiffe/spire/issues/1975) - For now, we will have a flat access model, which is equivalent to "Admin" flag of the SPIRE server. diff --git a/docs/tornjak-hints.md b/docs/tornjak-hints.md index d861f2e7..8a5d5d5c 100644 --- a/docs/tornjak-hints.md +++ b/docs/tornjak-hints.md @@ -1,8 +1,10 @@ # Debugging, Hints and Tips for Solving Common Problems with Tornjak + Here is a collection of various tips and hints for debugging deployment and runtime of Tornjak The hints collection is grouped in the following sections: + * [Tornjak Deployment](#tornjak-deployment) * [Tornjak Configuration](#tornjak-configuration) * [User Management](#user-management) @@ -19,15 +21,14 @@ The hints collection is grouped in the following sections: --- --> - ## Tornjak Deployment --- **Problem:** -SPIRE with Tornjak pod does not start. +SPIRE with Tornjak pod does not start. Status is `CrashLoopBackOff`. -The _spire-server_ container log shows: +The *spire-server* container log shows: ``` time="2022-11-11T22:47:23Z" level=info msg="Opening SQL database" db_type=sqlite3 subsystem_name=sql @@ -47,14 +48,14 @@ then delete the current DB on the host, and restart SPIRE so DB can be recreated with a correct version. -When _pvc_ is used to persist SPIRE data, delete it: +When *pvc* is used to persist SPIRE data, delete it: ```console kubectl -n spire-server get pvc kubectl -n spire-server delete pvc spire-data-spire-server-0 ``` -The _pvc_ will get recreated on the next deployment +The *pvc* will get recreated on the next deployment Otherwise, you can use this simple [DB clean tool](https://github.com/IBM/trusted-service-identity/blob/main/utils/spire.db.clean.yaml) to attach to the SPIRE server @@ -80,27 +81,31 @@ kubectl -n spire-server delete -f https://github.com/IBM/trusted-service-identit --- -**Problem:** +**Problem:** Pod with Tornjak front-end fails to start. Kubectl "Events" page shows the following: + ```console Startup probe failed: Get "http://172.17.0.3:3000/": context deadline exceeded (Client.Timeout exceeded while awaiting headers) ``` + Above message is accessible by (assuming `spire` namespace, `[POD]` is a placeholder for the front-end Pod name): + ```console kubectl -n spire-server describe po [POD] ``` **Description:** -_(Often encountered using Minikube)_ +*(Often encountered using Minikube)* Frontend does not compile in time. Cluster environment may be too weak to satisfy the startup probe within the allotted time. **Solution:** -Increase the `failureThreshold` in the Tornjak deployment file (look for _deployment.yaml_) under `startupProbe`: -```yaml +Increase the `failureThreshold` in the Tornjak deployment file (look for *deployment.yaml*) under `startupProbe`: + +```yaml failureThreshold: 15 ``` @@ -109,6 +114,7 @@ failureThreshold: 15 **Problem:** Agent log file shows an error: + ```console time="2021-10-01T15:26:14Z" level=info msg="SVID is not found. Starting node attestation" subsystem_name=attestor trust_domain_id="spiffe://openshift.com" time="2021-10-01T15:26:44Z" level=error msg="Agent crashed" error="create attestation client: failed to dial dns:///spire-server-tornjak.9d995c4a8c7c5f281ce13d5467ff6a94-0000.us-east.containers.appdomain.cloud:443: context deadline exceeded: connection error: desc = \"transport: authentication handshake failed: x509svid: could not verify leaf certificate: x509: certificate signed by unknown authority (possibly because of \\\"crypto/rsa: verification error\\\" while trying to verify candidate authority certificate \\\"SPIFFE\\\")\"" @@ -125,11 +131,13 @@ To update the "spire-bundle", get the `spire-bundle` configmap from the SPIRE server, update the namespace to match the agent cluster, then deploy it agent namespace. On the SPIRE server (assuming `spire-server` namespace): + ```console kubectl -n spire-server get configmap spire-bundle -oyaml | kubectl patch --type json --patch '[{"op": "replace", "path": "/metadata/namespace", "value":"spire"}]' -f - --dry-run=client -oyaml > spire-bundle.yaml ``` On the SPIRE agent cluster (assuming `spire` namespace): + ```console kubectl -n spire create -f spire-bundle.yaml ``` @@ -140,10 +148,6 @@ the agents will pick up the changes on the next restart. --- - - ## Tornjak Configuration - ## User Management - diff --git a/docs/tornjak-manager.md b/docs/tornjak-manager.md index c9c4d873..b3823751 100644 --- a/docs/tornjak-manager.md +++ b/docs/tornjak-manager.md @@ -1,8 +1,9 @@ -# Tornjak manager +# Tornjak manager ![tornjak-manager](rsrc/manager.png) The tornjak manager provides a way to manage identities, providing capabilities such as: + - Global visibility of identity registrations - Management of SPIRE identity configurations (Q) - Identity policy management @@ -12,47 +13,49 @@ The design idea behind the manager is to act as a thin layer between the user an ## Global visibility -Provide a dashboard of identity information and api calls to various spire servers through the tornjak agent. +Provide a dashboard of identity information and api calls to various spire servers through the tornjak agent. Actions possible: -- Register tornjak agent / spire server - - Provide address - - Choose authentication method - User or Certificate [pending auth issue #TBD] - - Engineering detail, for user, the credentials from the web browser of the user would be used to authenticate, if certificates, certificates will be provided and the backend would be responsible for authentication. i.e. AJAX/axios calls would be "https://adresss/api..." vs "/address/api" for user vs server - - Server + optional credentials are stored in the manager DB -- SPIRE API actions on servers - - frontend/backend for all SPIRE API actions -- Get server information + custom tornjak APIs - - This will include what are the plugins used in the server and pointing to logging and policy configurations for linking audit info. centrally - - frontend/backend for all custom tornjak API actions + +- Register tornjak agent / spire server + - Provide address + - Choose authentication method - User or Certificate [pending auth issue #TBD] + - Engineering detail, for user, the credentials from the web browser of the user would be used to authenticate, if certificates, certificates will be provided and the backend would be responsible for authentication. i.e. AJAX/axios calls would be "..." vs "/address/api" for user vs server + - Server + optional credentials are stored in the manager DB +- SPIRE API actions on servers + - frontend/backend for all SPIRE API actions +- Get server information + custom tornjak APIs + - This will include what are the plugins used in the server and pointing to logging and policy configurations for linking audit info. centrally + - frontend/backend for all custom tornjak API actions ## Identity policy management -- Provide an interface to the policy engines used by the SPIRE deployments -- Actions - - Add policy engine - - Provide address - - Choose authentication method - User or Certificate [pending auth issue #TBD] - - Visibility and consumability of policies - - Provide templates for more complex policies to be created - - CRUD on policies +- Provide an interface to the policy engines used by the SPIRE deployments +- Actions + - Add policy engine + - Provide address + - Choose authentication method - User or Certificate [pending auth issue #TBD] + - Visibility and consumability of policies + - Provide templates for more complex policies to be created + - CRUD on policies ## Auditability of Identities and use for operations/forensics -- Provide a collection of information, including logs, policy and registrations. This will include the statistics of use of SVIDs, minting, etc. - - May depend on additional features in SPIRE required -- Provide a way to consume this information or export the feed to another log consuming /metrics frontend. +- Provide a collection of information, including logs, policy and registrations. This will include the statistics of use of SVIDs, minting, etc. + - May depend on additional features in SPIRE required +- Provide a way to consume this information or export the feed to another log consuming /metrics frontend. ## Management of SPIRE Identity configurations Provide the ability to configure identities, including the ability to configure attestation configs, plugins, etc. Actions possible: -- Ability to set identity related configuration that is not exposed by the SPIRE API today, i.e.: - - Add a node attestor to a node - - Set workload registrar configuration -- These set of actions are tricky, which begs the question of whether some of these actions should be exposed via the SPIRE server API. - - These configurations are done today on the SPIRE server configuration file. Therefore it requires the management of the deployment in order + +- Ability to set identity related configuration that is not exposed by the SPIRE API today, i.e.: + - Add a node attestor to a node + - Set workload registrar configuration +- These set of actions are tricky, which begs the question of whether some of these actions should be exposed via the SPIRE server API. + - These configurations are done today on the SPIRE server configuration file. Therefore it requires the management of the deployment in order for these configurations to be managed for it. This raises some questions to be discussed about how to manage plugins. - - It is not straight forward for these to be managed by the tornjak agent because sometimes, these configurations are backed by non-traditional storage. + - It is not straight forward for these to be managed by the tornjak agent because sometimes, these configurations are backed by non-traditional storage. i.e. kubernetes configmap. In these cases, in order for the agent to be effective, it needs to be configured with knowledge of how to persist changes. diff --git a/docs/tornjak-ui-api-documentation.md b/docs/tornjak-ui-api-documentation.md index d2e76778..7e3a87b1 100644 --- a/docs/tornjak-ui-api-documentation.md +++ b/docs/tornjak-ui-api-documentation.md @@ -1,59 +1,59 @@ -#### Contents - -- [Tornjak UI-API Documentation](#1-tornjak-ui-api-documentation) - - [Overview](#11-overview) -- [Tornjak User Interface (UI) Architecture](#2-tornjak-user-interface-ui-architecture) - - [UI Pages (With their paths)](#21-ui-pages-with-their-paths) -- [Tornjak User Interface (UI) Interaction with API Endpoints](#3-tornjak-user-interface-ui-interaction-with-api-endpoints) - - [Agent API’s](#31-agent-apis) - - [Manager API’s](#32-manager-apis) -- [Tornjak Redux Reducers and Actions With Their Respective Descriptions -](#4-tornjak-redux-reducers-and-actions-with-their-respective-descriptions) - - [Reducers](#41-reducers) - - [Actions](#42-actions) +## Contents + +- [Tornjak UI-API Documentation](#1-tornjak-ui-api-documentation) + - [Overview](#11-overview) +- [Tornjak User Interface (UI) Architecture](#2-tornjak-user-interface-ui-architecture) + - [UI Pages (With their paths)](#21-ui-pages-with-their-paths) +- [Tornjak User Interface (UI) Interaction with API Endpoints](#3-tornjak-user-interface-ui-interaction-with-api-endpoints) + - [Agent API’s](#31-tornjak-apis) + - [Manager API’s](#32-manager-apis) +- [Tornjak Redux Reducers and Actions With Their Respective Descriptions](#4-tornjak-redux-reducers-and-actions-with-their-respective-descriptions) + - [Reducers](#41-reducers) + - [Actions](#42-actions) + # 1. Tornjak UI-API Documentation -### 1.1. Overview -This documentation details tornjak’s user interface and its interaction with the APIs and the redux state management. +## 1.1. Overview +This documentation details tornjak’s user interface and its interaction with the APIs and the redux state management. ![tornjak-high-level-ui-diagram](rsrc/tornjak-ui-diagram.png) - - - ![tornjak-high-level-back-end-diagram](rsrc/tornjak-backend-diagram.png) # 2. Tornjak User Interface (UI) Architecture -### 2.1. UI Pages (With their paths) -Below are UI pages of Tornjak with their respective paths. For details on a specific UI component and it’s interaction with the API calls refer to the diagrams respective to the pages by clicking on the link “Details”. There are two seperate UI’s, the manager UI and the regular agent UI. The regular agent UI is utilized for configuration and management of identities (For details visit [Agent design details](https://github.com/spiffe/tornjak/blob/main/docs/tornjak-agent.md)). The manager UI in addition to the regular agent UI includes the manager management panel/ page used to manage SPIRE servers (For details visit [Manager design details](https://github.com/spiffe/tornjak/blob/main/docs/tornjak-manager.md)). +## 2.1. UI Pages (With their paths) +Below are UI pages of Tornjak with their respective paths. For details on a specific UI component and it’s interaction with the API calls refer to the diagrams respective to the pages by clicking on the link “Details”. There are two seperate UI’s, the manager UI and the regular agent UI. The regular agent UI is utilized for configuration and management of identities (For details visit [Agent design details](https://github.com/spiffe/tornjak/blob/main/docs/tornjak-agent.md)). The manager UI in addition to the regular agent UI includes the manager management panel/ page used to manage SPIRE servers (For details visit [Manager design details](https://github.com/spiffe/tornjak/blob/main/docs/tornjak-manager.md)). -* Tornjak Home Page (/) - - [Details](rsrc/tornjak-agent-list.png) -* Agents Page (/agents || /agent/*) - - Agents List Page (/agents) +- Tornjak Home Page (/) - [Details](rsrc/tornjak-agent-list.png) - - Create Token Page (/agent/createjointoken) - - [Details](rsrc/tornjak-create-token.png) -* Entries Page (/entries || /entry/*) - - Entries List Page (/entries) - - [Details](rsrc/tornjak-entries-list.png) - - Create Entries Page (/entry/create) - - [Details](rsrc/tornjak-create-entries.png) -* Tornjak ServerInfo Page (/tornjak/serverinfo) - - [Details](rsrc/tornjak-serverInfo.png) -* Manage Servers Page (/server/manage) [ONLY FOR MANAGER UI] - - [Details](rsrc/tornjak-manage-servers.png) - +- Agents Page (/agents || /agent/*) + - Agents List Page (/agents) + - [Details](rsrc/tornjak-agent-list.png) + - Create Token Page (/agent/createjointoken) + - [Details](rsrc/tornjak-create-token.png) +- Entries Page (/entries || /entry/*) + - Entries List Page (/entries) + - [Details](rsrc/tornjak-entries-list.png) + - Create Entries Page (/entry/create) + - [Details](rsrc/tornjak-create-entries.png) +- Tornjak ServerInfo Page (/tornjak/serverinfo) + - [Details](rsrc/tornjak-serverInfo.png) +- Manage Servers Page (/server/manage) [ONLY FOR MANAGER UI] + - [Details](rsrc/tornjak-manage-servers.png) # 3. Tornjak User Interface (UI) Interaction with API Endpoints ## 3.1. Tornjak API’s + ### - [Healthcheck](https://pkg.go.dev/google.golang.org/grpc/health/grpc_health_v1#HealthCheckRequest) + #### GET + ##### /api/healthcheck + ``` Request api/healthcheck @@ -68,8 +68,11 @@ Content-Type: application/json; charset=utf-8 ``` ### - [DebugServer](https://github.com/spiffe/spire-api-sdk/tree/main/proto/spire/api/server/debug/v1) + #### GET + ##### /api/debugserver + ``` Request api/debugserver @@ -101,10 +104,12 @@ Content-Type: application/json; charset=utf-8 } ``` - ### - [Agents](https://github.com/spiffe/spire-api-sdk/tree/main/proto/spire/api/server/agent/v1) + #### GET + ##### /api/agent/list + ``` Request api/agent/list @@ -136,8 +141,11 @@ Content-Type: application/json; charset=utf-8 } } ``` + #### POST + ##### /api/agent/ban + ``` Request api/agent/ban @@ -154,7 +162,9 @@ Content-Type: application/json; charset=utf-8 Example response: SUCCESS ``` + ##### /api/agent/delete + ``` Request api/agent/delete @@ -171,7 +181,9 @@ Content-Type: application/json; charset=utf-8 Example response: SUCCESS ``` + ##### /api/agent/createjointoken + ``` Request api/agent/createjointoken @@ -192,9 +204,13 @@ Example response: } ``` + ### - [Entries](https://github.com/spiffe/spire-api-sdk/tree/main/proto/spire/api/server/entry/v1) + #### GET + ##### /api/entry/list + ``` Request api/entry/list @@ -227,8 +243,11 @@ Content-Type: application/json; charset=utf-8 } } ``` + #### POST + ##### /api/entry/create + ``` Request api/entry/create @@ -291,7 +310,9 @@ Example response: } } ``` + ##### /api/entry/delete + ``` Request api/entry/delete @@ -315,9 +336,13 @@ Example response: ] } ``` + ### - Tornjak Specific + #### GET + ##### /api/tornjak/serverinfo + ``` Request api/tornjak/serverinfo @@ -338,7 +363,9 @@ Content-Type: application/json; charset=utf-8 } ``` + ##### /api/tornjak/selectors/list + ``` Request api/tornjak/selectors/list @@ -355,6 +382,7 @@ Content-Type: application/json; charset=utf-8 ``` ##### /api/tornjak/clusters/list + ``` Request api/tornjak/clusters/list @@ -375,9 +403,10 @@ Content-Type: application/json; charset=utf-8 } ``` - #### POST + ##### /api/tornjak/selectors/register + ``` Request api/tornjak/selectors/register @@ -397,6 +426,7 @@ SUCCESS ``` ##### /api/tornjak/clusters/create + ``` Request api/tornjak/selectors/register @@ -418,6 +448,7 @@ SUCCESS ``` ##### /api/tornjak/clusters/edit + ``` Request api/tornjak/selectors/register @@ -440,6 +471,7 @@ SUCCESS ``` ##### /api/tornjak/clusters/delete + ``` Request api/tornjak/selectors/register @@ -457,14 +489,16 @@ Example response: SUCCESS ``` - - ## 3.2. Manager API’s -All of Tornjak agent APIs apply for manager APIs as well except that manager APIs are proxy calls of agent APIs (/manager-api/). In addition to the agent APIs manager API also includes server’s APIs as described below. + +All of Tornjak agent APIs apply for manager APIs as well except that manager APIs are proxy calls of agent APIs (/manager-api/). In addition to the agent APIs manager API also includes server’s APIs as described below. ### GET + #### - Servers + ##### /manager-api/server/list + ``` Request manager-api/server/list @@ -481,9 +515,13 @@ Example response: ] } ``` + ### POST + #### - Servers + ##### /manager-api/server/register + ``` Request manager-api/server/register @@ -503,6 +541,7 @@ Content-Type: application/json; charset=utf-8 Example response: SUCCESS ``` + ![tornjak-agent-list](rsrc/tornjak-agent-list.png) Figure 1. Agent List/ Home Page UI-API Interactions @@ -521,52 +560,54 @@ Figure 5. Tornjak ServerInfo Page UI-API Interactions ![tornjak-manage-servers](rsrc/tornjak-manage-servers.png) Figure 6. Manage Servers Page UI-API Interactions [ONLY FOR MANAGER UI] - # 4. Tornjak Redux Reducers and Actions With Their Respective Descriptions -Redux reducers are functions that mutate the current state based upon the defined action and generally as a developer one should be interfacing with the actions as those actions define the events that describe how and when the state is mutating in the application. One should only be creating reducers if modifying the data model is necessary. +Redux reducers are functions that mutate the current state based upon the defined action and generally as a developer one should be interfacing with the actions as those actions define the events that describe how and when the state is mutating in the application. One should only be creating reducers if modifying the data model is necessary. ## 4.1. [Reducers](https://github.com/spiffe/tornjak/tree/main/tornjak-frontend/src/redux/reducers) -- Servers - * Server Selected - - Stores the selected server in the redux state - * Server Info - - Stores the torjak server info of the selected server in the redux store - * Tornjak Server Info - - Stores the tornjak server info of the selected server in the redux store - * Servers List - - Stores the list of available servers and their basic info in the redux store - * Selector Info - - Stores the list of available selectors and their options in the redux store - * Workload Selector Info - - Stores the list of available workload selectors and their options in the redux store - -- Agents - * Agent List - - Stores the list of agents with their info in the redux store - * Agents Workload Attestor Info - - Stores the workload selector info for the agents in the redux store - -- Entries - * Entries List - - Stores the list of entries with their info in the redux store - -- Tornjak - * Tornjak Message - - Stores the Error Message/ Success Message of an executed function in the redux store + +- Servers + - Server Selected + - Stores the selected server in the redux state + - Server Info + - Stores the torjak server info of the selected server in the redux store + - Tornjak Server Info + - Stores the tornjak server info of the selected server in the redux store + - Servers List + - Stores the list of available servers and their basic info in the redux store + - Selector Info + - Stores the list of available selectors and their options in the redux store + - Workload Selector Info + - Stores the list of available workload selectors and their options in the redux store + +- Agents + - Agent List + - Stores the list of agents with their info in the redux store + - Agents Workload Attestor Info + - Stores the workload selector info for the agents in the redux store + +- Entries + - Entries List + - Stores the list of entries with their info in the redux store + +- Tornjak + - Tornjak Message + - Stores the Error Message/ Success Message of an executed function in the redux store ## 4.2. [Actions](https://github.com/spiffe/tornjak/tree/main/tornjak-frontend/src/redux/actions) -- TornjakMessage - * Expected input - "Error Message/ Success Message" - * This action returns the Error Message/ Success Message of an executed function -- ServerSelected - * Expected input - "ServerName" - * This action returns the server selected in the redux state -- TornjakServerInfoUpdate - * Expected input - "TornjakServerInfo" struct (as JSON) based on TornjakServerInfo in /api/types.go - * This action returns the tornjak server info of the selected server -- ServerInfoUpdate - * Expected input - + +- TornjakMessage + - Expected input - "Error Message/ Success Message" + - This action returns the Error Message/ Success Message of an executed function +- ServerSelected + - Expected input - "ServerName" + - This action returns the server selected in the redux state +- TornjakServerInfoUpdate + - Expected input - "TornjakServerInfo" struct (as JSON) based on TornjakServerInfo in /api/types.go + - This action returns the tornjak server info of the selected server +- ServerInfoUpdate + - Expected input - + ``` { "data": @@ -576,9 +617,11 @@ Redux reducers are functions that mutate the current state based upon the define } } ``` - * This action returns the server trust domain and nodeAttestorPlugin -- ServersListUpdate - * Expected input - + + - This action returns the server trust domain and nodeAttestorPlugin +- ServersListUpdate + - Expected input - + ``` [ "server1": @@ -597,9 +640,11 @@ Redux reducers are functions that mutate the current state based upon the define } ] ``` - * This action returns the list of available servers and their basic info -- SelectedInfo - * Expected input - + + - This action returns the list of available servers and their basic info +- SelectedInfo + - Expected input - + ``` [ "selector1": [ @@ -620,15 +665,17 @@ Redux reducers are functions that mutate the current state based upon the define ] ] ``` - * This action returns the list of available selectors and their options -- EntriesListUpdate - * Expected input - List of entries with their info json representation from [SPIFFE golang documentation](https://github.com/spiffe/spire/blob/v0.12.0/proto/spire/types/entry.pb.go#L28-L67) - * This action returns the list of entries with their info -- AgentsListUpdate - * Expected input - List of agents with their info json representation from [SPIFFE golang documentation](https://github.com/spiffe/spire/blob/v0.12.0/proto/spire/types/agent.pb.go#L28-L45) - * This action returns the list of agents with their info -- WorkloadSelectorInfo - * Expected input - + + - This action returns the list of available selectors and their options +- EntriesListUpdate + - Expected input - List of entries with their info json representation from [SPIFFE golang documentation](https://github.com/spiffe/spire/blob/v0.12.0/proto/spire/types/entry.pb.go#L28-L67) + - This action returns the list of entries with their info +- AgentsListUpdate + - Expected input - List of agents with their info json representation from [SPIFFE golang documentation](https://github.com/spiffe/spire/blob/v0.12.0/proto/spire/types/agent.pb.go#L28-L45) + - This action returns the list of agents with their info +- WorkloadSelectorInfo + - Expected input - + ``` [ "workloadselector1": [ @@ -649,9 +696,11 @@ Redux reducers are functions that mutate the current state based upon the define ] ] ``` - * This action returns the list of available workload selectors and their options -- AgentWorkloadSelectorInfo - * Expected input - + + - This action returns the list of available workload selectors and their options +- AgentWorkloadSelectorInfo + - Expected input - + ``` [ "agent1workloadselectorinfo": [ @@ -670,6 +719,5 @@ Redux reducers are functions that mutate the current state based upon the define ] ] ``` - * This action returns the workload selector info for the agents - + - This action returns the workload selector info for the agents diff --git a/docs/user-management.md b/docs/user-management.md index b6b88be5..7ea2226e 100644 --- a/docs/user-management.md +++ b/docs/user-management.md @@ -1,18 +1,18 @@ # User Management -This document compiles all the information on the integration of user management with Tornjak. +This document compiles all the information on the integration of user management with Tornjak. -Currently, user management is available only for a single instance of a Tornjak agent with a Frontend. +Currently, user management is available only for a single instance of a Tornjak agent with a Frontend. ## Overview We follow the OAuth2.0 spec for authentication. The diagrams below show the implemented [Standard Authorization Code Flow](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow): ![standard](./rsrc/standard-auth-code-flow.png) -We will eventually be implementing the [Authorization Code Flow with PKCE](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-proof-key-for-code-exchange-pkce) to secure the backend with a public frontend application. This is necessary as the public frontend cannot store client secrets securely: +We will eventually be implementing the [Authorization Code Flow with PKCE](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-proof-key-for-code-exchange-pkce) to secure the backend with a public frontend application. This is necessary as the public frontend cannot store client secrets securely: ![pkce](./rsrc/pkce-auth-code-flow.png) -A more in-depth Medium article for the overall architecture can be found [here](https://medium.com/universal-workload-identity/identity-access-management-iam-integration-with-tornjak-749984966ab5). +A more in-depth Medium article for the overall architecture can be found [here](https://medium.com/universal-workload-identity/identity-access-management-iam-integration-with-tornjak-749984966ab5). ## Architecture @@ -24,26 +24,27 @@ The architecture integrates with a separate Auth server. This Auth server is use User management requires the following: -* There must be an existing, pre-configured Auth Server to integrate with Tornjak (e.g. Keycloak) -* The Tornjak Backend is deployed with a configuration pointing to said Auth Server. -* The Tornjak Frontend must be deployed configured to obtain access tokens from said Auth Server before sending calls to the Tornjak Backend. +* There must be an existing, pre-configured Auth Server to integrate with Tornjak (e.g. Keycloak) +* The Tornjak Backend is deployed with a configuration pointing to said Auth Server. +* The Tornjak Frontend must be deployed configured to obtain access tokens from said Auth Server before sending calls to the Tornjak Backend. ## Examples and Tutorials -We have experimented extensively with the open source Keycloak Auth Server. -Specifically, it is very easy to set up a Tornjak secured by Keycloak today, by following these steps: +We have experimented extensively with the open source Keycloak Auth Server. +Specifically, it is very easy to set up a Tornjak secured by Keycloak today, by following these steps: -1. **Configure Auth Server** +1. **Configure Auth Server** To configure the Auth Server, please see our [Medium blog](https://medium.com/universal-workload-identity/step-by-step-guide-to-setup-keycloak-configuration-for-tornjak-dbe5c3049034) for a walkthrough on configuring the Auth Server. For more in-depth documentation on this setup, please see [this document on Keycloak configuration](./keycloak-configuration.md). -Alternatively, see [our keycloak example](/examples/keycloak) for ready deployment files into your local Kubernetes cluster. +Alternatively, see [our keycloak example](/examples/keycloak) for ready deployment files into your local Kubernetes cluster. -1. **Enable User Management for Tornjak Backend** -Once the Auth Server is set up, we can deploy the Tornjak Backend to require access tokens from our Auth Server, -as detailed in -[this followup Medium blog](https://medium.com/universal-workload-identity/guide-to-integrating-tornjak-with-keycloak-for-access-control-to-spire-40a3d5ee5f5a), -with more details on the general configuration +1. **Enable User Management for Tornjak Backend** +Once the Auth Server is set up, we can deploy the Tornjak Backend to require access tokens from our Auth Server, +as detailed in +[this followup Medium blog](https://medium.com/universal-workload-identity/guide-to-integrating-tornjak-with-keycloak-for-access-control-to-spire-40a3d5ee5f5a), +with more details on the general configuration [here](/docs/config-tornjak-server.md). Most notably, populate a new plugin section for keycloak as defined [here](/docs/plugin_server_auth_keycloak.md) like so: + ``` ... Authenticator "Keycloak" { @@ -58,10 +59,10 @@ with more details on the general configuration ... ``` -1. **Configure Tornjak Frontend** -Finally, the Frontend must be deployed and configured to obtain access tokens from this auth server. -This can be done locally with the environment variable -`REACT_APP_AUTH_SERVER_URI`. In addition `REACT_APP_KEYCLOAK_REALM` and `REACT_APP_OIDC_CLIENT_ID` must be set as well. +1. **Configure Tornjak Frontend** +Finally, the Frontend must be deployed and configured to obtain access tokens from this auth server. +This can be done locally with the environment variable +`REACT_APP_AUTH_SERVER_URI`. In addition `REACT_APP_KEYCLOAK_REALM` and `REACT_APP_OIDC_CLIENT_ID` must be set as well. Default values are: @@ -90,6 +91,6 @@ Please be patient, as it might take a few minutes to compile and start the serve For a cloud deployment change the URLs accordingly using the cloud provider ingress. -Given the Auth Server configuration above, we have an `admin` and a `viewer` user type. -An Admin User has an admin level privileges allowing create, configure, and delete operations. +Given the Auth Server configuration above, we have an `admin` and a `viewer` user type. +An Admin User has an admin level privileges allowing create, configure, and delete operations. The Viewer User has a restricted access for the Tornjak UI, allowing only read and list operations. diff --git a/frontend/.npmrc b/frontend/.npmrc new file mode 100644 index 00000000..3de71f24 --- /dev/null +++ b/frontend/.npmrc @@ -0,0 +1,4 @@ +registry=https://registry.npmjs.com/ +save-prefix=^ +shrinkwrap=true +legacy-peer-deps=true \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b50f9d55..04ef1f54 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -46,6 +46,7 @@ "redux-thunk": "^2.3.0", "stringify-object": "^4.0.1", "tss-react": "^4.8.4", + "typescript": "5.0.3", "url-join": "^4.0.1", "web-vitals": "^0.2.4" }, @@ -67,6 +68,7 @@ "identity-obj-proxy": "^3.0.0", "jest": "^27.2.2", "jest-transform-stub": "^2.0.0", + "markdownlint-cli2": "^0.7.1", "moxios": "^0.4.0", "nodemon": "^2.0.13", "puppeteer": "^22.11.2", @@ -4003,126 +4005,6 @@ "node": ">= 10" } }, - "node_modules/@next/swc-darwin-x64": { - "version": "14.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.10.tgz", - "integrity": "sha512-Y0TC+FXbFUQ2MQgimJ/7Ina2mXIKhE7F+GUe1SgnzRmwFY3hX2z8nyVCxE82I2RicspdkZnSWMn4oTjIKz4uzA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.10.tgz", - "integrity": "sha512-ZfQ7yOy5zyskSj9rFpa0Yd7gkrBnJTkYVSya95hX3zeBG9E55Z6OTNPn1j2BTFWvOVVj65C3T+qsjOyVI9DQpA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.10.tgz", - "integrity": "sha512-n2i5o3y2jpBfXFRxDREr342BGIQCJbdAUi/K4q6Env3aSx8erM9VuKXHw5KNROK9ejFSPf0LhoSkU/ZiNdacpQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.10.tgz", - "integrity": "sha512-GXvajAWh2woTT0GKEDlkVhFNxhJS/XdDmrVHrPOA83pLzlGPQnixqxD8u3bBB9oATBKB//5e4vpACnx5Vaxdqg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.10.tgz", - "integrity": "sha512-opFFN5B0SnO+HTz4Wq4HaylXGFV+iHrVxd3YvREUX9K+xfc4ePbRrxqOuPOFjtSuiVouwe6uLeDtabjEIbkmDA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.10.tgz", - "integrity": "sha512-9NUzZuR8WiXTvv+EiU/MXdcQ1XUvFixbLIMNQiVHuzs7ZIFrJDLJDaOF1KaqttoTujpcxljM/RNAOmw1GhPPQQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.10.tgz", - "integrity": "sha512-fr3aEbSd1GeW3YUMBkWAu4hcdjZ6g4NBl1uku4gAn661tcxd1bHs1THWYzdsbTRLcCKLjrDZlNp6j2HTfrw+Bg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.10.tgz", - "integrity": "sha512-UjeVoRGKNL2zfbcQ6fscmgjBAS/inHBh63mjIlfPg/NG8Yn2ztqylXt5qilYb6hoHIwaU2ogHknHWWmahJjgZQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -14911,6 +14793,15 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/linkify-it": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -15115,11 +15006,169 @@ "tmpl": "1.0.5" } }, + "node_modules/markdown-it": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", + "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/markdownlint": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.28.2.tgz", + "integrity": "sha512-yYaQXoKKPV1zgrFsyAuZPEQoe+JrY9GDag9ObKpk09twx4OCU5lut+0/kZPrQ3W7w82SmgKhd7D8m34aG1unVw==", + "dev": true, + "dependencies": { + "markdown-it": "13.0.1", + "markdownlint-micromark": "0.1.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/markdownlint-cli2": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.7.1.tgz", + "integrity": "sha512-N58lw50Ws0WOfCc07B9dPKMnPMbIj6ZCMlszZLVfxBwKN/M+WZqXLdOHyRL2BWCZ3APBxQN9qDEw7Vf1PRqFkg==", + "dev": true, + "dependencies": { + "globby": "13.1.4", + "markdownlint": "0.28.2", + "markdownlint-cli2-formatter-default": "0.0.4", + "micromatch": "4.0.5", + "strip-json-comments": "5.0.0", + "yaml": "2.2.2" + }, + "bin": { + "markdownlint-cli2": "markdownlint-cli2.js", + "markdownlint-cli2-config": "markdownlint-cli2-config.js", + "markdownlint-cli2-fix": "markdownlint-cli2-fix.js" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/markdownlint-cli2-formatter-default": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.4.tgz", + "integrity": "sha512-xm2rM0E+sWgjpPn1EesPXx5hIyrN2ddUnUwnbCsD/ONxYtw3PX6LydvdH6dciWAoFDpwzbHM1TO7uHfcMd6IYg==", + "dev": true, + "peerDependencies": { + "markdownlint-cli2": ">=0.0.4" + } + }, + "node_modules/markdownlint-cli2/node_modules/globby": { + "version": "13.1.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", + "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdownlint-cli2/node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/markdownlint-cli2/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdownlint-cli2/node_modules/strip-json-comments": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", + "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdownlint-cli2/node_modules/yaml": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", + "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/markdownlint-micromark": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.2.tgz", + "integrity": "sha512-jRxlQg8KpOfM2IbCL9RXM8ZiYWz2rv6DlZAnGv8ASJQpUh6byTBnEsbuMZ6T2/uIgntyf7SKg/mEaEBo1164fQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -19283,23 +19332,6 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, - "node_modules/sass": { - "version": "1.69.7", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.7.tgz", - "integrity": "sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==", - "peer": true, - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/sass-loader": { "version": "12.6.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", @@ -21001,16 +21033,15 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "peer": true, + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", + "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/ua-parser-js": { @@ -21035,6 +21066,12 @@ "node": "*" } }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 35bc5101..5692da3a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -41,6 +41,7 @@ "redux-thunk": "^2.3.0", "stringify-object": "^4.0.1", "tss-react": "^4.8.4", + "typescript": "5.0.3", "url-join": "^4.0.1", "web-vitals": "^0.2.4" }, @@ -58,7 +59,9 @@ "test": "react-scripts test -env=jsdom", "coverage": "react-scripts test -env=jsdom --watchAll=false --coverage", "eject": "react-scripts eject", - "dev": "concurrently -k -n COMPILER,NODEMON -c yellow,blue \"tsc -w\" \"nodemon -w dist -q dist/index.js\"" + "dev": "concurrently -k -n COMPILER,NODEMON -c yellow,blue \"tsc -w\" \"nodemon -w dist -q dist/index.js\"", + "lint": "markdownlint-cli2 '../docs/*.md' --config '../.markdownlint.yml' '!node_modules' '!../.markdownlint.yml'", + "lint:fix": "markdownlint-cli2-fix '../docs/*.md' --config '../.markdownlint.yml' '!node_modules' '!../.markdownlint.yml'" }, "eslintConfig": { "extends": [ @@ -101,7 +104,8 @@ "puppeteer": "^22.11.2", "react-inject-env": "^2.1.0", "react-test-renderer": "^18.2.0", - "redux-mock-store": "^1.5.4" + "redux-mock-store": "^1.5.4", + "markdownlint-cli2": "^0.7.1" }, "jest": { "moduleNameMapper": {