Browse Source

feat: add docs (#39)

* feat: add docs

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
Moritz Johner 5 years ago
parent
commit
7b883778e9
49 changed files with 2375 additions and 4 deletions
  1. 21 0
      .github/workflows/docs.yml
  2. 2 0
      .gitignore
  3. 11 0
      Makefile
  4. 1 1
      README.md
  5. 6 0
      docs/.mkdocs-exclude
  6. 5 0
      docs/api-clustersecretstore.md
  7. 17 0
      docs/api-externalsecret.md
  8. 113 0
      docs/api-overview.md
  9. 9 0
      docs/api-secretstore.md
  10. 82 0
      docs/contributing-devguide.md
  11. 32 0
      docs/contributing-process.md
  12. 62 0
      docs/guides-getting-started.md
  13. 8 0
      docs/guides-introduction.md
  14. 66 0
      docs/guides-multi-tenancy.md
  15. 3 0
      docs/guides-templating.md
  16. 46 0
      docs/index.md
  17. BIN
      docs/pictures/diagrams-high-level-cluster-detail.png
  18. BIN
      docs/pictures/diagrams-high-level-ns-detail.png
  19. BIN
      docs/pictures/diagrams-high-level-simple.png
  20. BIN
      docs/pictures/diagrams-multi-tenancy-managed-store.png
  21. BIN
      docs/pictures/diagrams-multi-tenancy-self-service.png
  22. BIN
      docs/pictures/diagrams-multi-tenancy-shared.png
  23. BIN
      docs/pictures/diagrams-resource-mapping.png
  24. 1 0
      docs/pictures/diagrams.drawio
  25. BIN
      docs/pictures/eso-az-kv-aws-sm.png
  26. BIN
      docs/pictures/eso-az-kv-azure-kv.png
  27. 7 0
      docs/provider-aws-parameter-store.md
  28. 40 0
      docs/provider-aws-secrets-manager.md
  29. 2 0
      docs/provider-azure-key-vault.md
  30. 5 0
      docs/provider-google-secrets-manager.md
  31. 5 0
      docs/provider-hashicorp-vault.md
  32. 20 0
      docs/snippets/aws-sm-store.yaml
  33. 21 0
      docs/snippets/basic-external-secret.yaml
  34. 18 0
      docs/snippets/basic-secret-store.yaml
  35. 97 0
      docs/snippets/full-external-secret.yaml
  36. 48 0
      docs/snippets/full-secret-store.yaml
  37. 8 0
      docs/snippets/namespace-permitted-annotation.yaml
  38. 24 0
      docs/snippets/provider-aws-access.md
  39. 1183 0
      docs/spec.md
  40. 0 3
      go.sum
  41. 21 0
      hack/api-docs/Dockerfile
  42. 77 0
      hack/api-docs/Makefile
  43. 25 0
      hack/api-docs/config.json
  44. 53 0
      hack/api-docs/generate.sh
  45. 48 0
      hack/api-docs/members.tpl
  46. 44 0
      hack/api-docs/mkdocs.yml
  47. 48 0
      hack/api-docs/pkg.tpl
  48. 17 0
      hack/api-docs/requirements.txt
  49. 79 0
      hack/api-docs/type.tpl

+ 21 - 0
.github/workflows/docs.yml

@@ -0,0 +1,21 @@
+name: github pages
+on:
+  push:
+    branches:
+      - main
+jobs:
+  deploy:
+    runs-on: ubuntu-18.04
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Build
+        run: make docs
+
+      - name: Deploy
+        uses: peaceiris/actions-gh-pages@v3
+        with:
+          github_token: ${{ secrets.GITHUB_TOKEN }}
+          publish_dir: ./site

+ 2 - 0
.gitignore

@@ -11,3 +11,5 @@ cover.out
 **/charts/**/requirements.lock
 **/charts/**/requirements.lock
 
 
 deploy/charts/external-secrets/templates/crds/*.yaml
 deploy/charts/external-secrets/templates/crds/*.yaml
+
+site/

+ 11 - 0
Makefile

@@ -181,6 +181,17 @@ helm.generate:
 	done
 	done
 	@$(OK) Finished generating helm chart files
 	@$(OK) Finished generating helm chart files
 
 
+
+# ====================================================================================
+# Documentation
+.PHONY: docs
+docs: generate
+	$(MAKE) -C ./hack/api-docs build
+
+.PHONY: serve-docs
+serve-docs:
+	$(MAKE) -C ./hack/api-docs serve
+
 # ====================================================================================
 # ====================================================================================
 # Build Artifacts
 # Build Artifacts
 
 

+ 1 - 1
README.md

@@ -13,7 +13,7 @@ Multiple people and organizations are joining efforts to create a single Externa
 
 
 # ⚠️ Please bear in mind
 # ⚠️ Please bear in mind
 
 
-While this project is not ready, you might consider using the following: 
+While this project is not ready, you might consider using the following:
 
 
 - [Kubernetes External Secrets](https://github.com/external-secrets/kubernetes-external-secrets)
 - [Kubernetes External Secrets](https://github.com/external-secrets/kubernetes-external-secrets)
 - [Secrets Manager](https://github.com/itscontained/secret-manager)
 - [Secrets Manager](https://github.com/itscontained/secret-manager)

+ 6 - 0
docs/.mkdocs-exclude

@@ -0,0 +1,6 @@
+.mkdocs-exclude
+.nojekyll
+.placeholder
+search/search_index.json
+sitemap.xml.gz
+sitemap.xml

+ 5 - 0
docs/api-clustersecretstore.md

@@ -0,0 +1,5 @@
+![ClusterSecretStore](./pictures/diagrams-high-level-cluster-detail.png)
+
+The `ClusterSecretStore` is a cluster scoped SecretStore that can be used by all
+`ExternalSecrets` from all namespaces unless you pin down its usage by using
+RBAC or Admission Control.

+ 17 - 0
docs/api-externalsecret.md

@@ -0,0 +1,17 @@
+The `ExternalSecret` describes what data should be fetched, how the data should
+be transformed and saved as a `Kind=Secret`:
+
+* tells the operator what secrets should be synced by using `spec.data` to
+  explicitly sync individual keys or use `spec.dataFrom` to get **all values**
+  from the external API.
+* you can specify how the secret should look like by specifying a
+  `spec.target.template`
+
+## Example
+
+Take a look at an annotated example to understand the design behind the
+`ExternalSecret`.
+
+``` yaml
+{% include 'full-external-secret.yaml' %}
+```

+ 113 - 0
docs/api-overview.md

@@ -0,0 +1,113 @@
+# API Overview
+
+## Architecture
+![high-level](./pictures/diagrams-high-level-simple.png)
+
+The External Secrets Operator extends Kubernetes with [Custom
+Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/),
+which define where secrets live and how to synchronize them. The controller
+fetches secrets from an external API and creates Kubernetes
+[secrets](https://kubernetes.io/docs/concepts/configuration/secret/). If the
+secret from the external API changes, the controller will reconcile the state in
+the cluster and update the secrets accordingly.
+
+
+## Resource model
+
+To understand the mechanics of the operator let's start with the data model. The
+SecretStore references an bucket of key/value pairs. But because every external
+API is slightly different this bucket may be e.g. an instance of an Azure
+KeyVault or a AWS Secrets Manager in a certain AWS Account and region. Please
+take a look at the provider documentation to see what the Bucket actually maps
+to.
+
+![Resource Mapping](./pictures/diagrams-resource-mapping.png)
+
+### SecretStore
+
+The idea behind the `SecretStore` resource is to separate concerns of
+authentication/access and the actual Secret and configuration needed for
+workloads. The ExternalSecret specifies what to fetch, the SecretStore specifies
+how to access. This resource is namespaced.
+
+``` yaml
+{% include 'basic-secret-store.yaml' %}
+```
+The `SecretStore` contains references to secrets which hold credentials to
+access the external API.
+
+### ExternalSecret
+An ExternalSecret declares what data to fetch. It has a reference to a
+`SecretStore` which knows how to access that data. The controller uses that
+`ExternalSecret` as a blueprint to create secrets.
+
+``` yaml
+{% include 'basic-external-secret.yaml' %}
+```
+
+### ClusterSecretStore
+
+The `ClusterSecretStore` is just a global, cluster-wide SecretStore that can be
+referenced from all namespaces.
+
+## Behavior
+
+The External Secret Operator (ESO for brevity) reconciles `ExternalSecrets` in
+the following manner:
+
+1. ESO uses `spec.secretStoreRef` to find an appropriate `SecretStore`. If it
+   doesn't exist or the `spec.controller` field doesn't match it won't further
+   process this ExternalSecret.
+2. ESO instanciates an external API client using the specified credentials from
+   the `SecretStore` spec.
+3. ESO fetches the secrets as requested by the `ExternalSecret`, it will decode
+   the secrets if required
+5. ESO creates an `Kind=Secret` based on the template provided by
+   `ExternalSecret.target.template`. The `Secret.data` can be templated using
+   the secret values from the external API.
+6. ESO ensures that the secret values stay in sync with the external API
+
+## Roles and responsibilities
+
+The External Secret Operator is designed to target the following persona:
+
+* **Cluster Operator**: The cluster operator is responsible for setting up the
+  External Secret Operator, managing access policies and creating
+  ClusterSecretStores.
+* **Application developer**: The Application developer is responsible for
+  defining ExternalSecrets and the application configuration
+
+Each persona will roughly map to a Kubernetes RBAC role. Depending on your
+environment these roles can map to a single user. **Note:** There is no Secret
+Operator that handles the lifecycle of the secret, this is out of the scope of
+ESO.
+
+## Access Control
+
+The External Secrets Operator runs as a deployment in your cluster with elevated
+privileges. It will create/read/update secrets in all namespaces and has access
+to secrets stored in some external API. Ensure that the credentials you provide
+give ESO the least privilege necessary.
+
+Design your `SecretStore`/`ClusterSecretStore` carefully! Use annotations on
+namespaces to restrict access of application developers to read only certain
+keys in a shared environment.
+
+``` yaml
+{% include 'namespace-permitted-annotation.yaml' %}
+```
+
+!!! bug "Not implemented"
+    This is currently **not yet** implemented. Feel free to contribute.
+
+You should also consider using Kubernetes' admission control system (e.g.
+[OPA](https://www.openpolicyagent.org/) or [Kyverno](https://kyverno.io/)) for
+fine-grained access control.
+
+## Running multiple Controller
+You can run multiple controller within the cluster. One controller can be
+limited to only process `SecretStores` with a predefined `spec.controller`
+field.
+
+!!! note "Testers welcome"
+    This is not widely tested. Please help us test the setup and/or document use-cases.

+ 9 - 0
docs/api-secretstore.md

@@ -0,0 +1,9 @@
+![SecretStore](./pictures/diagrams-high-level-ns-detail.png)
+
+
+The `SecretStore` is namespaced and specifies how to access the external API.
+The SecretStore maps to exactly one instance of an external API.
+
+``` yaml
+{% include 'full-secret-store.yaml' %}
+```

+ 82 - 0
docs/contributing-devguide.md

@@ -0,0 +1,82 @@
+## Getting Started
+
+You must have a working [Go environment](https://golang.org/doc/install) and
+then clone the repo:
+
+```shell
+git clone https://github.com/external-secrets/external-secrets.git
+cd external-secrets
+```
+
+## Building & Testing
+
+The project uses the `make` build system. It'll run code generators, tests and
+static code analysis.
+
+Building the operator binary and docker image:
+
+```shell
+make build
+make docker-build IMG=external-secrets:latest
+```
+
+Run tests and lint the code:
+```shell
+make test
+make lint
+```
+
+Build the documentation:
+```shell
+make docs
+```
+
+## Installing
+
+To install the External Secret Operator's CRDs into a Kubernetes Cluster run:
+
+```shell
+make install
+```
+
+Apply the sample resources:
+```shell
+kubectl apply -f config/samples/external-secrets_v1alpha1_secretstore.yaml
+kubectl apply -f config/samples/external-secrets_v1alpha1_externalsecret.yaml
+```
+
+You can run the controller on your host system for development purposes:
+
+```shell
+make run
+```
+
+To remove the CRDs run:
+
+```shell
+make uninstall
+```
+
+!!! note "Contributing Flow"
+    The HOW TO guide for contributing is at the [Contributing Process](contributing-process.md) page.
+
+
+## Documentation
+
+We use [mkdocs material](https://squidfunk.github.io/mkdocs-material/) to generate this
+documentation. See `/docs` for the source code and `/hack/api-docs` for the build process.
+
+When writing documentation it is advised to run the mkdocs server with livereload:
+
+```shell
+make serve-docs
+```
+
+Run the following command to run a complete build. The rendered assets are available under `/site`.
+
+```shell
+make docs
+
+# inspect the build with this one-liner
+python -m http.server 8000 --directory site
+```

+ 32 - 0
docs/contributing-process.md

@@ -0,0 +1,32 @@
+## Project Management
+The Code, our TODOs and Documentation is maintained on
+[GitHub](https://github.com/external-secrets/external-secrets). All Issues
+should be opened in that repository.
+
+## Issues
+
+Features, bugs and any issues regarding the documentation should be filed as
+[GitHub Issue](https://github.com/external-secrets/external-secrets/issues) in
+our repository. We use labels like `kind/feature`, `kind/bug`, `area/aws` to
+organize the issues. Issues labeled `good first issue` and `help wanted` are
+especially good for a first contribution. If you want to pick up an issue just
+leave a comment.
+
+## Submitting a Pull Request
+
+This project uses the well-known pull request process from GitHub. Merging a
+pull request requires the following steps to be completed before the pull
+request will be merged:
+
+* ideally, there is an issue that documents the problem or feature in depth.
+* code must have a reasonable amount of test coverage
+* tests must pass
+* PR needs be reviewed and approved
+
+Once these steps are completed the PR will be merged by a code owner.
+
+
+## Cutting Releases
+
+As of now this project is in an early alpha phase. There is just the main branch
+;)

+ 62 - 0
docs/guides-getting-started.md

@@ -0,0 +1,62 @@
+# Getting started with Services APIs
+
+## Installing CRDs
+
+This project provides a collection of Custom Resource Definitions (CRDs) that
+can be installed into any Kubernetes (>= 1.16) cluster.
+
+To install the CRDs, please execute:
+
+``` bash
+kubectl kustomize "github.com/external-secrets/external-secrets/config/crd" \
+| kubectl apply -f -
+```
+
+## Install the controller
+
+``` bash
+kubectl kustomize "github.com/external-secrets/external-secrets/config/default" \
+| kubectl apply -f -
+```
+
+### Create your first SecretStore
+
+``` yaml
+{% include 'basic-secret-store.yaml' %}
+```
+
+### Create your first ExternalSecret
+
+``` yaml
+{% include 'basic-external-secret.yaml' %}
+```
+
+``` bash
+kubectl describe externalsecret example
+# [...]
+Name:  example
+Status:
+  Conditions:
+    Last Transition Time:  2021-02-24T16:45:23Z
+    Message:               Secret was synced
+    Reason:                SecretSynced
+    Status:                True
+    Type:                  Ready
+  Refresh Time:            2021-02-24T16:45:24Z
+Events:                    <none>
+```
+
+For more advanced examples, please read the other
+[guides](guides-introduction.md).
+
+## Uninstalling the CRDs
+
+To uninstall the CRDs and all resources created with them, run the following
+command. Note that this will remove all ExternalSecrets and SecretStore
+resources in your cluster. If you have been using these resources for any other
+purpose do not uninstall these CRDs.
+
+```
+kubectl kustomize "github.com/external-secrets/external-secrets/config/crd" \
+| kubectl delete -f -
+```

+ 8 - 0
docs/guides-introduction.md

@@ -0,0 +1,8 @@
+# Guides
+
+The following guides demonstrate use-cases and provide examples of how to use
+the API. Please pick one of the following guides:
+
+* [Getting started](guides-getting-started.md)
+* [Advanced Templating](guides-templating.md)
+* [Multi-Tenancy Design Considerations](guides-multi-tenancy.md)

+ 66 - 0
docs/guides-multi-tenancy.md

@@ -0,0 +1,66 @@
+External Secrets Operator provides different modes of operation to fulfill
+ogranizational needs. This guide outlines the flexibility of ESO and should give
+you a first impression of how you can employ this operator in your organization.
+
+For a multi-tenant deployment you should first examine your organizational
+structure:
+
+1. what roles (i.e. *Application Developers*, *Cluster Admins*, ...) do you have
+   in your organization,
+2. what responsibilities do they have and
+3. how does that map to Kubernetes RBAC roles.
+
+Further, you should examine how your external API provider manages access
+control for your secrets. Can you limit access by secret names (e.g.
+`db/dev/*`)? Or only on a bucket level? Please keep in mind that not all
+external APIs provide fine-grained access management for secrets.
+
+**Note:** The following examples should **not** be considered as best practice
+but rather as a example to show how to combine different mechanics and
+techniques for tenant isolation.
+
+### Shared ClusterSecretStore
+
+![Shared CSS](./pictures/diagrams-multi-tenancy-shared.png)
+
+A Cluster Administrator deploys a `ClusterSecretStore` (CSS) and manages access
+to the external API. The CSS is shared by all tenants within the cluster.
+Application Developers do reference it in a `ExternalSecret` but can not create
+a ClusterSecretStores or SecretStores on their own. Now all application
+developers have access to all the secrets. You probably want to limit access to
+certain keys or prefixes that should be used. ESO provides a very simple
+mechanic to limit access to certain keys on a namespace basis by using
+annotations on the `Kind=Namespace` resource. More advanced validation should be
+done with an Admission Webhook, e.g. with [Kyverno](https://kyverno.io/) or
+[Open Policy Agent](https://www.openpolicyagent.org/)).
+
+``` yaml
+{% include 'namespace-permitted-annotation.yaml' %}
+```
+
+This setup suites well if you have one central bucket that contains all of your
+secrets and your Cluster Administrators should manage access to it. This setup
+is very simple but does not scale very well.
+
+### Managed SecretStore per Namespace
+
+![Shared CSS](./pictures/diagrams-multi-tenancy-managed-store.png)
+
+Cluster Administrators manage one or multipe `SecretStores` per Namespace. Each
+SecretStore uses it's own *role* that limits access to a small set of keys. The
+peculiarity of this is approach is, that **access is actually managed by the
+external API** which provides the roles. The Cluster Administrator does just the
+wiring. This approach may be desirable if you have an external entity - let's
+call it **Secret Administrator** - that manages access and lifecycle of the
+secrets.
+
+
+### ESO as a Service
+![Shared CSS](./pictures/diagrams-multi-tenancy-self-service.png)
+
+Every namespace is self-contained. Application developers manage `SecretStore`,
+`ExternalSecret` and secret infrastructure on their own. Cluster Administrators
+*just* provide the External Secrets Operator as a service.
+
+This makes sense if application developers should be completely autonomous while
+a central team provides common services.

+ 3 - 0
docs/guides-templating.md

@@ -0,0 +1,3 @@
+!!! note "Not implemented"
+    This is currently **not yet** implemented. See [#28](https://github.com/external-secrets/external-secrets/issues/28)
+    for details. Feel free to contribute.

+ 46 - 0
docs/index.md

@@ -0,0 +1,46 @@
+# Introduction
+
+![high-level](./pictures/diagrams-high-level-simple.png)
+
+**External Secrets Operator** is a Kubernetes operator that integrates external
+secret management systems like [AWS Secrets
+Manager](https://aws.amazon.com/secrets-manager/), [HashiCorp
+Vault](https://www.vaultproject.io/), [Google Secrets
+Manager](https://cloud.google.com/secret-manager), [Azure Key
+Vault](https://azure.microsoft.com/en-us/services/key-vault/) and many more. The
+operator reads information from external APIs and automatically injects the
+values into a [Kubernetes
+Secret](https://kubernetes.io/docs/concepts/configuration/secret/).
+
+### What is the goal of External Secrets Operator?
+
+The goal of External Secrets Operator is to synchronize secrets from external
+APIs into Kubernetes. ESO is a collection of custom API resources -
+`ExternalSecret`, `SecretStore` and `ClusterSecretStore` that provide a
+user-friendly abstraction for the external API that stores and manages the
+lifecycle of the secrets for you.
+
+### Where to get started
+
+To get started, please read through [API overview](api-overview.md) this should
+give you a high-level overview to understand the API and use-cases. After that
+please follow one of our [guides](guides-introduction.md) to get a jump start
+using the operator.
+
+For a complete reference of the API types please refer to our [API
+Reference](spec.md).
+
+### How to get involved
+
+This project is driven by it's users and contributors and we welcome everybody
+to get involved. Join our meetings, open issues or ask questions in Slack. The
+success of this project depends on your input: No contribution is too small -
+even opinions matter!
+
+How to get involved:
+
+- Monthly Meeting: we announce our meetings on slack
+  ([agenda](https://hackmd.io/GSGEpTVdRZCP6LDxV3FHJA))
+- [Kubernetes Slack
+  #external-secrets](https://kubernetes.slack.com/messages/external-secrets)
+- [Contributing Process](contributing-process.md)

BIN
docs/pictures/diagrams-high-level-cluster-detail.png


BIN
docs/pictures/diagrams-high-level-ns-detail.png


BIN
docs/pictures/diagrams-high-level-simple.png


BIN
docs/pictures/diagrams-multi-tenancy-managed-store.png


BIN
docs/pictures/diagrams-multi-tenancy-self-service.png


BIN
docs/pictures/diagrams-multi-tenancy-shared.png


BIN
docs/pictures/diagrams-resource-mapping.png


File diff suppressed because it is too large
+ 1 - 0
docs/pictures/diagrams.drawio


BIN
docs/pictures/eso-az-kv-aws-sm.png


BIN
docs/pictures/eso-az-kv-azure-kv.png


+ 7 - 0
docs/provider-aws-parameter-store.md

@@ -0,0 +1,7 @@
+
+!!! bug "Not implemented"
+    This is currently **not yet** implemented. Feel free to contribute. Please see
+    [issue#27](https://github.com/external-secrets/external-secrets/issues/27)
+    for futher information.
+
+--8<-- "snippets/provider-aws-access.md"

+ 40 - 0
docs/provider-aws-secrets-manager.md

@@ -0,0 +1,40 @@
+
+![aws sm](./pictures/eso-az-kv-aws-sm.png)
+
+
+--8<-- "snippets/provider-aws-access.md"
+
+
+## Secrets Manager
+
+A `SecretStore` points to AWS Secrets Manager in a certain account within a
+defined region. You should define Roles that allow fine-grained access to
+individual secrets and pass them to ESO using `spec.provider.awssm.role`. This
+way users of the `SecretStore` can only access the secrets necessary.
+
+``` yaml
+{% include 'aws-sm-store.yaml' %}
+```
+
+
+Create a IAM Policy to pin down access to secrets matching `dev-*`.
+
+``` json
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": [
+        "secretsmanager:GetResourcePolicy",
+        "secretsmanager:GetSecretValue",
+        "secretsmanager:DescribeSecret",
+        "secretsmanager:ListSecretVersionIds"
+      ],
+      "Resource": [
+        "arn:aws:secretsmanager:us-west-2:111122223333:secret:dev-*",
+      ]
+    }
+  ]
+}
+```

+ 2 - 0
docs/provider-azure-key-vault.md

@@ -0,0 +1,2 @@
+
+![aws sm](./pictures/eso-az-kv-azure-kv.png)

+ 5 - 0
docs/provider-google-secrets-manager.md

@@ -0,0 +1,5 @@
+
+!!! bug "Not implemented"
+    This is currently **not yet** implemented. Feel free to contribute.
+    Please see [issue#33](https://github.com/external-secrets/external-secrets/issues/33)
+    for futher information.

+ 5 - 0
docs/provider-hashicorp-vault.md

@@ -0,0 +1,5 @@
+
+!!! bug "Not implemented"
+    This is currently **not yet** implemented. Feel free
+    to contribute. Please see [issue#21](https://github.com/external-secrets/external-secrets/issues/21)
+    for futher information.

+ 20 - 0
docs/snippets/aws-sm-store.yaml

@@ -0,0 +1,20 @@
+apiVersion: external-secrets.io/v1alpha1
+kind: SecretStore
+metadata:
+  name: secretstore-sample
+spec:
+  controller: dev
+  provider:
+    awssm:
+      # define a specific role to limit access
+      # to certain secrets
+      role: iam-role
+      region: eu-central-1
+      auth:
+        secretRef:
+          accessKeyIDSecretRef:
+            name: awssm-secret
+            key: access-key
+          secretAccessKeySecretRef:
+            name: awssm-secret
+            key: secret-access-key

+ 21 - 0
docs/snippets/basic-external-secret.yaml

@@ -0,0 +1,21 @@
+apiVersion: external-secrets.io/v1alpha1
+kind: ExternalSecret
+metadata:
+  name: example
+spec:
+  refreshInterval: 1h
+  secretStoreRef:
+    name: secretstore-sample
+    kind: SecretStore
+  target:
+    name: secret-to-be-created
+    creationPolicy: Owner
+  data:
+  - secretKey: secret-key-to-be-managed
+    remoteRef:
+      key: provider-key
+      version: provider-key-version
+      property: provider-key-property
+  dataFrom:
+  - remoteRef:
+    key: remote-key-in-the-provider

+ 18 - 0
docs/snippets/basic-secret-store.yaml

@@ -0,0 +1,18 @@
+apiVersion: external-secrets.io/v1alpha1
+kind: SecretStore
+metadata:
+  name: secretstore-sample
+spec:
+  controller: dev
+  provider:
+    awssm:
+      role: arn:aws:iam::123456789012:role/team-a-reader
+      region: us-east-1
+      auth:
+        secretRef:
+          accessKeyIDSecretRef:
+            name: awssm-secret
+            key: access-key
+          secretAccessKeySecretRef:
+            name: awssm-secret
+            key: secret-access-key

+ 97 - 0
docs/snippets/full-external-secret.yaml

@@ -0,0 +1,97 @@
+{% raw %}
+apiVersion: external-secrets.io/v1alpha1
+kind: ExternalSecret
+metadata:
+  name: "hello-world"
+
+  # labels and annotations are copied over to the
+  # secret that will be created
+  labels:
+    acme.org/owned-by: "q-team"
+  annotations:
+    acme.org/sha: 1234
+
+spec:
+
+  # SecretStoreRef defines which SecretStore to use when fetching the secret data
+  secretStoreRef:
+    name: secret-store-name
+    kind: SecretStore  # or ClusterSecretStore
+
+  # RefreshInterval is the amount of time before the values reading again from the SecretStore provider
+  # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" (from time.ParseDuration)
+  # May be set to zero to fetch and create it once
+  refreshInterval: "1h"
+
+  # the target describes the secret that shall be created
+  # there can only be one target per ExternalSecret
+  target:
+
+    # The secret name of the resource
+    # Defaults to .metadata.name of the ExternalSecret
+    # It is immutable
+    name: my-secret
+
+    # Enum with values: 'Owner', 'Merge', or 'None'
+    # Default value of 'Owner'
+    # Owner creates the secret and sets .metadata.ownerReferences of the resource
+    # Merge does not create the secret, but merges in the data fields to the secret
+    # None does not create a secret (future use with injector)
+    creationPolicy: 'Merge'
+
+    # Specify a blueprint for the resulting Kind=Secret
+    template:
+      type: kubernetes.io/dockerconfigjson # or TLS...
+
+      metadata:
+        annotations: {}
+        labels: {}
+
+      # Use inline templates to construct your desired config file that contains your secret
+      data:
+        config.yml: |
+          endpoints:
+          - https://{{ .data.user }}:{{ .data.password }}@api.exmaple.com
+
+      # Uses an existing template from configmap
+      # Secret is fetched, merged and templated within the referenced configMap data
+      # It does not update the configmap, it creates a secret with: data["alertmanager.yml"] = ...result...
+      templateFrom:
+      - configMap:
+          name: alertmanager
+          items:
+          - key: alertmanager.yaml
+
+  # Data defines the connection between the Kubernetes Secret keys and the Provider data
+  data:
+    - secretKey: secret-key-to-be-managed
+      remoteRef:
+        key: provider-key
+        version: provider-key-version
+        property: provider-key-property
+
+  # Used to fetch all properties from the Provider key
+  # If multiple dataFrom are specified, secrets are merged in the specified order
+  dataFrom:
+  - remoteRef:
+      key: provider-key
+      version: provider-key-version
+      property: provider-key-property
+
+status:
+  # refreshTime is the time and date the external secret was fetched and
+  # the target secret updated
+  refreshTime: "2019-08-12T12:33:02Z"
+  # Standard condition schema
+  conditions:
+  # ExternalSecret ready condition indicates the secret is ready for use.
+  # This is defined as:
+  # - The target secret exists
+  # - The target secret has been refreshed within the last refreshInterval
+  # - The target secret content is up-to-date based on any target templates
+  - type: Ready
+    status: "True" # False if last refresh was not successful
+    reason: "SecretSynced"
+    message: "Secret was synced"
+    lastTransitionTime: "2019-08-12T12:33:02Z"
+{% endraw %}

+ 48 - 0
docs/snippets/full-secret-store.yaml

@@ -0,0 +1,48 @@
+apiVerson: external-secrets.io/v1alpha1
+kind: SecretStore
+metadata:
+  name: vault
+  namespace: example-ns
+spec:
+
+  # Used to select the correct ESO controller (think: ingress.ingressClassName)
+  # The ESO controller is instantiated with a specific controller name and filters ES based on this property
+  # Optional
+  controller: dev
+
+  # provider field contains the configuration to access the provider which contains the secret
+  # exactly one provider must be configured.
+  provider:
+
+    # (1): AWS Secrets Manager
+    # AWSSM configures this store to sync secrets using AWS Secret Manager provider
+    awssm:
+      # Role is a Role ARN which the SecretManager provider will assume
+      role: iam-role
+      # AWS Region to be used for the provider
+      region: eu-central-1
+      # Auth defines the information necessary to authenticate against AWS by
+      # getting the accessKeyID and secretAccessKey from an already created Kubernetes Secret
+      auth:
+        secretRef:
+          accessKeyID:
+            name: awssm-secret
+            key: access-key
+          secretAccessKey:
+            name: awssm-secret
+            key: secret-access-key
+
+    # (TODO): add more provider examples here
+
+status:
+  # Standard condition schema
+  conditions:
+  # SecretStore ready condition indicates the given store is in ready
+  # state and able to referenced by ExternalSecrets
+  # If the `status` of this condition is `False`, ExternalSecret controllers
+  # should prevent attempts to fetch secrets
+  - type: Ready
+    status: "False"
+    reason: "ConfigError"
+    message: "SecretStore validation failed"
+    lastTransitionTime: "2019-08-12T12:33:02Z"

+ 8 - 0
docs/snippets/namespace-permitted-annotation.yaml

@@ -0,0 +1,8 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: team-a
+  annotations:
+    # annotation that defines which keys can be read
+    # the annotation value is a regular expression
+    external-secrets.io/permitted-key-name: "a/development/*"

+ 24 - 0
docs/snippets/provider-aws-access.md

@@ -0,0 +1,24 @@
+## AWS Authentication
+
+Access to AWS providers can be granted in various ways:
+
+* [IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html): IAM roles for service accounts.
+* Per pod IAM authentication: [kiam](https://github.com/uswitch/kiam) or [kube2iam](https://github.com/jtblin/kube2iam).
+* Directly provide AWS credentials to the External Secrets Operator pod by using environment variables.
+
+Additionally, before fetching a secret from a store, ESO is able to assume role (as a proxy so to speak). It is advisable to use multiple roles in a multi-tenant environment.
+
+
+You can limit the range of roles which can be assumed by this particular namespace by using annotations on the namespace resource. The annotation value is evaluated as a regular expression.
+
+!!! bug "Not implemented"
+    This is currently **not** implemented. Feel free to contribute.
+
+``` yaml
+kind: Namespace
+metadata:
+  name: iam-example
+  annotations:
+    # annotation key is configurable
+    iam.amazonaws.com/permitted: "arn:aws:iam::123456789012:role/foo.*"
+```

File diff suppressed because it is too large
+ 1183 - 0
docs/spec.md


+ 0 - 3
go.sum

@@ -68,7 +68,6 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
 github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
 github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
 github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
-github.com/aws/aws-sdk-go v1.27.0 h1:0xphMHGMLBrPMfxR2AmVjZKcMEESEgWF8Kru94BNByk=
 github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go v1.35.24 h1:U3GNTg8+7xSM6OAJ8zksiSM4bRqxBWmVwwehvOSNG3A=
 github.com/aws/aws-sdk-go v1.35.24 h1:U3GNTg8+7xSM6OAJ8zksiSM4bRqxBWmVwwehvOSNG3A=
 github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
 github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
@@ -285,7 +284,6 @@ github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
 github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
 github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
 github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
 github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
@@ -874,7 +872,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
 gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
 gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 21 - 0
hack/api-docs/Dockerfile

@@ -0,0 +1,21 @@
+# Copyright 2019 The Kubernetes Authors.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM alpine:3.11
+
+COPY requirements.txt /
+RUN apk add -U --no-cache \
+    python3 \
+    bash \
+    diffutils \
+  && pip3 install -r /requirements.txt

+ 77 - 0
hack/api-docs/Makefile

@@ -0,0 +1,77 @@
+# Copyright 2019 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+DOCKER ?= docker
+MKDOCS_IMAGE ?= github.com/external-secrets-mkdocs:latest
+MKDOCS ?= mkdocs
+SERVE_BIND_ADDRESS ?= 127.0.0.1
+
+# TOP is the current directory where this Makefile lives.
+TOP := $(dir $(firstword $(MAKEFILE_LIST)))
+# ROOT is the repository root.
+ROOT := $(abspath $(TOP))/../../
+SRCDIR := $(ROOT)/docs
+CFGFILE := $(ROOT)/hack/api-docs/mkdocs.yml
+# GENROOT is the root of the generated documentation.
+GENROOT := $(ROOT)/site
+
+# Grab the uid/gid to fix permissions due to running in a docker container.
+GID := $(shell id -g)
+UID := $(shell id -u)
+
+# SOURCES is a list of a source files used to generate the documentation.
+SOURCES := $(shell find $(SRCDIR) -name \*.md)
+SOURCES += mkdocs.yml Makefile
+
+# entrypoint
+all: build
+
+.PHONY: image
+image:
+	$(DOCKER) build -t $(MKDOCS_IMAGE) -f Dockerfile .
+
+.PHONY: build
+build: image generate $(SOURCES)
+	mkdir -p $(GENROOT)
+	$(DOCKER) run \
+		--mount type=bind,source=$(SRCDIR),target=/docs \
+		--mount type=bind,source=$(CFGFILE),target=/mkdocs.yml \
+		--mount type=bind,source=$(GENROOT),target=/site \
+		--sig-proxy=true \
+		--rm \
+		$(MKDOCS_IMAGE) \
+		/bin/bash -c "cd / && $(MKDOCS) build; find /site -exec chown $(UID):$(GID) {} \;"
+
+.PHONY: generate
+generate:
+	./generate.sh $(SRCDIR)/spec.md
+
+.PHONY: clean
+clean:
+	rm -r $(GENROOT)/* || true
+
+# serve runs mkdocs as a local webserver for interactive development.
+# This will serve the live copy of the docs on 127.0.0.1:8000.
+.PHONY: serve
+serve:
+	$(DOCKER) run \
+		-it \
+		--sig-proxy=true \
+		--mount type=bind,source=$(SRCDIR),target=/docs \
+		--mount type=bind,source=$(CFGFILE),target=/mkdocs.yml \
+		--mount type=bind,source=$(GENROOT),target=/site \
+		-p $(SERVE_BIND_ADDRESS):8000:8000 \
+		--rm \
+		$(MKDOCS_IMAGE) \
+		/bin/bash -c "cd / && $(MKDOCS) serve -a 0.0.0.0:8000"

+ 25 - 0
hack/api-docs/config.json

@@ -0,0 +1,25 @@
+{
+    "hideMemberFields": [
+        "TypeMeta"
+    ],
+    "hideTypePatterns": [
+        "ParseError$",
+        "List$",
+        "^StoreProvider$"
+    ],
+    "externalPackages": [
+        {
+            "typeMatchPrefix": "^k8s\\.io/apimachinery/pkg/apis/meta/v1\\.Time$",
+            "docsURLTemplate": "https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Time"
+        },
+        {
+            "typeMatchPrefix": "^k8s\\.io/(api|apimachinery/pkg/apis)/",
+            "docsURLTemplate": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#{{lower .TypeIdentifier}}-{{arrIndex .PackageSegments -1}}-{{arrIndex .PackageSegments -2}}"
+        }
+    ],
+    "typeDisplayNamePrefixOverrides": {
+        "k8s.io/api/": "Kubernetes ",
+        "k8s.io/apimachinery/pkg/apis/": "Kubernetes "
+    },
+    "markdownDisabled": false
+}

+ 53 - 0
hack/api-docs/generate.sh

@@ -0,0 +1,53 @@
+#!/bin/bash
+
+# Copyright 2020 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+GOPATH=${GOPATH:-$(go env GOPATH)}
+
+# "go env" doesn't print anything if GOBIN is the default, so we
+# have to manually default it.
+GOBIN=${GOBIN:-$(go env GOBIN)}
+GOBIN=${GOBIN:-${GOPATH}/bin}
+
+readonly HERE=$(cd $(dirname $0) && pwd)
+readonly REPO=$(cd ${HERE}/../.. && pwd)
+
+gendoc::build() {
+    go install github.com/ahmetb/gen-crd-api-reference-docs
+}
+
+# Exec the doc generator.
+gendoc::exec() {
+    local readonly confdir="${REPO}/hack/api-docs"
+
+    ${GOBIN}/gen-crd-api-reference-docs \
+        -template-dir ${confdir} \
+        -config ${confdir}/config.json \
+        "$@"
+}
+
+if [ "$#" != "1" ]; then
+    echo "usage: generate.sh OUTFILE"
+    exit 2
+fi
+
+gendoc::build
+gendoc::exec \
+    -api-dir github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1 \
+    -out-file "$1"

+ 48 - 0
hack/api-docs/members.tpl

@@ -0,0 +1,48 @@
+{{ define "members" }}
+
+{{ range .Members }}
+{{ if not (hiddenMember .)}}
+<tr>
+    <td>
+        <code>{{ fieldName . }}</code></br>
+        <em>
+            {{ if linkForType .Type }}
+                <a href="{{ linkForType .Type}}">
+                    {{ typeDisplayName .Type }}
+                </a>
+            {{ else }}
+                {{ typeDisplayName .Type }}
+            {{ end }}
+        </em>
+    </td>
+    <td>
+        {{ if fieldEmbedded . }}
+            <p>
+                (Members of <code>{{ fieldName . }}</code> are embedded into this type.)
+            </p>
+        {{ end}}
+
+        {{ if isOptionalMember .}}
+            <em>(Optional)</em>
+        {{ end }}
+
+        {{ safe (renderComments .CommentLines) }}
+
+    {{ if and (eq (.Type.Name.Name) "ObjectMeta") }}
+        Refer to the Kubernetes API documentation for the fields of the
+        <code>metadata</code> field.
+    {{ end }}
+
+    {{ if or (eq (fieldName .) "spec") }}
+        <br/>
+        <br/>
+        <table>
+            {{ template "members" .Type }}
+        </table>
+    {{ end }}
+    </td>
+</tr>
+{{ end }}
+{{ end }}
+
+{{ end }}

+ 44 - 0
hack/api-docs/mkdocs.yml

@@ -0,0 +1,44 @@
+site_name: External Secrets Opereator
+repo_url: https://github.com/external-secrets/external-secrets
+repo_name: External Secrets Operator
+site_dir: site
+docs_dir: docs
+theme:
+  name: material
+markdown_extensions:
+  - pymdownx.highlight
+  - pymdownx.superfences
+  - admonition
+  - pymdownx.snippets:
+      base_path: docs
+plugins:
+  - search:
+      lang: en
+  - macros:
+      include_dir: docs/snippets
+nav:
+  - Introduction: index.md
+  - Overview: api-overview.md
+  - API Types:
+      ExternalSecret: api-externalsecret.md
+      SecretStore: api-secretstore.md
+      ClusterSecretStore: api-clustersecretstore.md
+  - Guides:
+    - Introduction: guides-introduction.md
+    - Getting started: guides-getting-started.md
+    - Advanced Templating: guides-templating.md
+    - Multi Tenancy: guides-multi-tenancy.md
+  - Provider:
+    - AWS:
+      - Secrets Manager: provider-aws-secrets-manager.md
+      - Parameter Store: provider-aws-parameter-store.md
+    - Azure:
+      - Key Vault: provider-azure-key-vault.md
+    - Google:
+      - Secrets Manager: provider-google-secrets-manager.md
+    - HashiCorp Vault: provider-hashicorp-vault.md
+  - References:
+    - API specification: spec.md
+  - Contributing:
+    - Developer guide: contributing-devguide.md
+    - Contributing Process: contributing-process.md

+ 48 - 0
hack/api-docs/pkg.tpl

@@ -0,0 +1,48 @@
+{{ define "packages" }}
+
+{{ with .packages}}
+<p>Packages:</p>
+<ul>
+    {{ range . }}
+    <li>
+        <a href="#{{- packageAnchorID . -}}">{{ packageDisplayName . }}</a>
+    </li>
+    {{ end }}
+</ul>
+{{ end}}
+
+{{ range .packages }}
+    <h2 id="{{- packageAnchorID . -}}">
+        {{- packageDisplayName . -}}
+    </h2>
+
+    {{ with (index .GoPackages 0 )}}
+        {{ with .DocComments }}
+        <p>
+            {{ safe (renderComments .) }}
+        </p>
+        {{ end }}
+    {{ end }}
+
+    Resource Types:
+    <ul>
+    {{- range (visibleTypes (sortedTypes .Types)) -}}
+        {{ if isExportedType . -}}
+        <li>
+            <a href="{{ linkForType . }}">{{ typeDisplayName . }}</a>
+        </li>
+        {{- end }}
+    {{- end -}}
+    </ul>
+
+    {{ range (visibleTypes (sortedTypes .Types))}}
+        {{ template "type" .  }}
+    {{ end }}
+    <hr/>
+{{ end }}
+
+<p><em>
+    Generated with <code>gen-crd-api-reference-docs</code>.
+</em></p>
+
+{{ end }}

+ 17 - 0
hack/api-docs/requirements.txt

@@ -0,0 +1,17 @@
+Click==7.0
+htmlmin==0.1.12
+Jinja2==2.10.3
+jsmin==2.2.2
+livereload==2.6.1
+Markdown==3.1.1
+MarkupSafe==1.1.1
+mkdocs==1.0.4
+mkdocs-material==4.6.0
+mkdocs-minify-plugin==0.2.1
+pep562==1.0
+Pygments==2.5.2
+pymdown-extensions==6.2.1
+PyYAML==5.3
+six==1.14.0
+tornado==6.0.3
+mkdocs-macros-plugin==0.4.18

+ 79 - 0
hack/api-docs/type.tpl

@@ -0,0 +1,79 @@
+{{ define "type" }}
+
+<h3 id="{{ anchorIDForType . }}">
+    {{- .Name.Name }}
+    {{ if eq .Kind "Alias" }}(<code>{{.Underlying}}</code> alias)</p>{{ end -}}
+</h3>
+{{ with (typeReferences .) }}
+    <p>
+        (<em>Appears on:</em>
+        {{- $prev := "" -}}
+        {{- range . -}}
+            {{- if $prev -}}, {{ end -}}
+            {{ $prev = . }}
+            <a href="{{ linkForType . }}">{{ typeDisplayName . }}</a>
+        {{- end -}}
+        )
+    </p>
+{{ end }}
+
+
+<p>
+    {{ safe (renderComments .CommentLines) }}
+</p>
+
+{{ with (constantsOfType .) }}
+<table>
+    <thead>
+        <tr>
+            <th>Value</th>
+            <th>Description</th>
+        </tr>
+    </thead>
+    <tbody>
+      {{- range . -}}
+      <tr>
+        {{- /* renderComments implicitly creates a <p> element, so we do the
+               same here to make the value line up nicely.  */ -}}
+        <td><p>{{ typeDisplayName . }}</p></td>
+        <td>{{ safe (renderComments .CommentLines) }}</td>
+      </tr>
+      {{- end -}}
+    </tbody>
+</table>
+{{ end }}
+
+{{ if .Members }}
+<table>
+    <thead>
+        <tr>
+            <th>Field</th>
+            <th>Description</th>
+        </tr>
+    </thead>
+    <tbody>
+        {{ if isExportedType . }}
+        <tr>
+            <td>
+                <code>apiVersion</code></br>
+                string</td>
+            <td>
+                <code>
+                    {{apiGroup .}}
+                </code>
+            </td>
+        </tr>
+        <tr>
+            <td>
+                <code>kind</code></br>
+                string
+            </td>
+            <td><code>{{.Name.Name}}</code></td>
+        </tr>
+        {{ end }}
+        {{ template "members" .}}
+    </tbody>
+</table>
+{{ end }}
+
+{{ end }}