From 116426ecb2d5cafc450819470eb5abf0313b0ef3 Mon Sep 17 00:00:00 2001
From: Ce Gao
Date: Sun, 31 May 2020 10:50:09 +0800
Subject: [PATCH 1/2] feat(proposals): Refine
Signed-off-by: Ce Gao
---
proposals/artifact-processor-extender.md | 349 ++++++++++++++----
.../artifact-processor-extender/arch.png | Bin 0 -> 76418 bytes
.../current-design.png | Bin 0 -> 44443 bytes
.../extend-problem-1.png | Bin 0 -> 87131 bytes
.../extend-problem-2.png | Bin 0 -> 83060 bytes
.../workflow-new.png | Bin 0 -> 114228 bytes
.../artifact-processor-extender/workflow.png | Bin 0 -> 95774 bytes
7 files changed, 274 insertions(+), 75 deletions(-)
create mode 100644 proposals/images/artifact-processor-extender/arch.png
create mode 100644 proposals/images/artifact-processor-extender/current-design.png
create mode 100644 proposals/images/artifact-processor-extender/extend-problem-1.png
create mode 100644 proposals/images/artifact-processor-extender/extend-problem-2.png
create mode 100644 proposals/images/artifact-processor-extender/workflow-new.png
create mode 100644 proposals/images/artifact-processor-extender/workflow.png
diff --git a/proposals/artifact-processor-extender.md b/proposals/artifact-processor-extender.md
index cd592561..0a9c0cb6 100644
--- a/proposals/artifact-processor-extender.md
+++ b/proposals/artifact-processor-extender.md
@@ -1,33 +1,178 @@
+
+
+**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
+
+- [Proposal: `Artifact Processor Extender`](#proposal-artifact-processor-extender)
+ - [Abstract](#abstract)
+ - [Background](#background)
+ - [Motivation](#motivation)
+ - [Goals](#goals)
+ - [Non-Goals](#non-goals)
+ - [Implementation](#implementation)
+ - [HTTPProcessor and Processor Extender](#httpprocessor-and-processor-extender)
+ - [`HTTPProcessor`](#httpprocessor)
+ - [Processor Extender](#processor-extender)
+ - [Configuration file `processors.yaml`](#configuration-file-processorsyaml)
+ - [Artifact Data Access](#artifact-data-access)
+ - [Policy Check Interceptor](#policy-check-interceptor)
+ - [OAuth 2 Bearer Tokens](#oauth-2-bearer-tokens)
+ - [Robot Accounts](#robot-accounts)
+ - [Development Process](#development-process)
+ - [First Iteration: HTTPProcessor and Extender without Auth](#first-iteration-httpprocessor-and-extender-without-auth)
+ - [Second Iteration: Registration](#second-iteration-registration)
+ - [Third Iteration: Auth in the Processor Extender](#third-iteration-auth-in-the-processor-extender)
+
+
+
# Proposal: `Artifact Processor Extender`
-Author: `Ce Gao @gaocegege, Jian Zhu @zhujian7, Yiyang Huang @hyy0322`
+Author:
+
+- Yiyang Huang [@hyy0322](https://github.com/hyy0322) \ (Corresponding Author)
+- Ce Gao [@gaocegege](https://github.com/gaocegege)
+- Jian Zhu [@zhujian7](https://github.com/zhujian7)
+
+Links:
-Discussion: [goharbor/harbor#12013](https://github.com/goharbor/harbor/issues/12013)
+- Discussion: [goharbor/harbor#12013](https://github.com/goharbor/harbor/issues/12013)
+- Slides: [Feature Request: Harbor Artifact Processor Extender](https://docs.google.com/presentation/d/1rX7v9IhXjXEAmbJP29nkSU2RJXUrpLJujL8iemqcjnU/edit#)
## Abstract
-Add support to Harbor for using remote artifact processor to process user defined OCI Artifact.
+Harbor v2.0 makes Harbor the first OCI-compliant open source registry capable of storing a multitude of cloud-native artifacts like container images, Helm charts, OPAs, Singularity, and much more. It found strong demand on extending artifact types to support more complex scenarios. But the artifact authors now have to implement the processing logic in Harbor Core, which is not extensible.
-## Background
+The current design might go against the adoption of Harbor in industries since there are always proprietary artifact types. Thus we design the artifact processor extender to address the problem in this proposal. When new custom artifact types are registered into Harbor Core, the core service will communicate with the remote artifact processor extender via RESTful API. Artifact-specific logic will keep in the extender, and the Harbor Core will be artifact-neutral.
-There are four types of artifacts, which are image, helm v3, CNAB, OPA bundle, supported by Harbor. Each of them implements its processor to abstract metadata into artifact model defined by harbor. If users want to define a new kind of artifact, they need to implement the processor logic in goharbor/harbor core service, which greatly limits the scalability and extensibility of Harbor.
+## Background
-## Proposal
+There are four types of artifacts, which are image, helm v3, CNAB, OPA bundle, supported by Harbor. Each of them implements its processor to abstract metadata into artifact model defined by harbor. If users want to define a new kind of artifact, they have to implement the processor logic in Harbor Core service, which greatly limits the scalability and extensibility of Harbor.
-To achieve the goal of making harbor have the ability to process user defined aitifact whthout adding code in harhor core service which makes harbor extensible in extracting artifact data, the current build-in processor logic interface can be abstract to HTTP API.
+## Motivation
-New Component:
-1. Remote Processor API - HTTP API defining interface between Harbor and remote processor.
- i. Defined and maintained by Harbor
- ii. Authentication specifics are out-of-scope, but should be supported using the HTTP ```Authorization``` header
-2. Remote Processor - HTTP service that implements the Remote Processor API to extracte artifact data.
- i.Deployed outside the system boundary of Harbor, not considered an internal component
- ii.Implementations are out-of-tree of Harbor
- iii.Has independent state management, configuration, and deployment lifecycle from Harbor
+When we use Harbor to store custom artifacts, we cannot get the expected result from the API provided by Harbor `{}/api/v2.0/projects/{}/repositories/{}/artifacts/{}`. For example, we store a new artifact using [caicloud/ormb](https://github.com/caicloud/ormb), which is a OCI artifact specification for Machine Learning models, we get the result from the API:
-```Processor``` interface is defined in Harbor, which is used to process the specified artifact.
+```
+{
+ "digest": "sha256:123aa..",
+ "id": 2,
+ "manifest_media_type": "application/vnd.oci.image.manifest.v1+json",
+ "media_type": "application/vnd.caicloud.model.config.v1alpha1+json",
+ "project_id": 2,
+ "repository_id": 1,
+ "size": 12927980,
+ "tags": [
+ {
+ "artifact_id": 2,
+ "id": 2,
+ "immutable": false,
+ "name": "v1",
+ "pull_time": "0001-01-01T00:00:00.000Z",
+ "push_time": "2020-05-15T04:04:19.516Z",
+ "repository_id": 2,
+ "signed": false
+ }
+ ],
+ "type": "MODEL"
+}
+```
+But when we store the Helm Chart and send request to the same API, we get more attributes. The extra attributes store the content of the config layer of the Helm Chart. Thus we can think the result is self-contained.
+
+```diff
+{
++ "extra_attrs": {
++ "apiVersion": "v1",
++ "appVersion": "0.8.0",
++ "description": "Host your own Helm Chart Repository",
++ "home": "https://github.com/helm/chartmuseum",
++ "icon": "https://raw.githubusercontent.com/helm/chartmuseum/master/logo2.png",
++ "keywords": [
++ "chartmuseum",
++ ],
++ "maintainers": [
++ {
++ "email": "opensource@codefresh.io",
++ "name": "codefresh-io"
++ }
++ ],
++ "name": "chartmuseum",
++ "version": "1.8.2"
++ },
+ "digest": "sha256:123aa..",
+ "id": 1,
+ "manifest_media_type": "application/vnd.oci.image.manifest.v1+json",
+ "media_type": "application/vnd.cncf.helm.config.v1+json",
+ "project_id": 2,
+ "repository_id": 2,
+ "size": 12927980,
+ "tags": [
+ {
+ "artifact_id": 1,
+ "id": 1,
+ "immutable": false,
+ "name": "v1",
+ "pull_time": "0001-01-01T00:00:00.000Z",
+ "push_time": "2020-05-15T04:04:19.516Z",
+ "repository_id": 2,
+ "signed": false
+ }
+ ],
+ "type": "CHART"
+}
```
+
+The self-contained response is also necessary for these user-defined artifact types. Or we cannot use Harbor directly for most scenarios. The `extra_attrs` field is processed by the Helm Chart processor, which is an implementation of artifact processor interface `Processor`.
+
+The current design of the artifact processor is shown in Fig. 1. `Processor` interface is defined in Harbor Core, and there are four implementations for different types which embeds `base.IndexProcessor` and `base.ManifestProcessor`.
+
+
+
+
Fig. 1 Current Design of Harbor Artifact Processor
+
+
+When artifact authors extend the artifact types, they implement corresponding processor logic in Harbor Core, as shown in Fig. 2. For example, there will be four new processor implementations in Harbor Core with at least four different maintainers from different communities if we want to support these four artifact types.
+
+
+
+
Fig. 2 More Harbor Artifact Processor in Harbor Core
+
+
+Besides this, there will be more proprietary artifact types in industries, just like Kubernetes CRDs, as shown in Fig. 3. Each artifact vendor has to maintain their own fork to keep their proprietary artifact types, which may make Harbor a fragmented platform.
+
+
+
+
Fig. 3 Fragmented Problems in Harbor
+
+
+## Goals
+
+This proposal is to:
+
+- Design the new processor to extend artifact types in runtime.
+- Keep non-invasive to the current built-in processors, at the same time.
+
+## Non-Goals
+
+This proposal is not to:
+
+- Support whitelist for artifact types. [goharbor/harbor#12061](https://github.com/goharbor/harbor/issues/12061)
+
+## Implementation
+
+To address these problems, we propose a new feature **artifact processor extender** in Harbor Core. Some contributions have been made in this proposal:
+
+- The new Processor struct `HTTPProcessor` to support artifact processor extender feature for extending custom artifact types. The current design of `Processor` interface is not changed at the same time, thus the new feature will not affect the existing supported types like OCI Image, CNAB and Helm Chart.
+
+- The new configuration file `processors.yaml` to register artifact types with processors in runtime.
+
+- The similar mechanism to Scanner to support Auth in `HTTPProcessor`, which will be used to pull manifests from the Registry.
+
+
+### HTTPProcessor and Processor Extender
+
+The Processor interface is defined in Harbor Core and we do not propose any change for it.
+
+```go
// Processor processes specified artifact
type Processor interface {
// GetArtifactType returns the type of one kind of artifact specified by media type
@@ -44,17 +189,21 @@ type Processor interface {
}
```
-```Registry``` is defined to store ```Processor```.
+We propose a new implementation of the `Processor` interface, `HTTPProcessor`. The design of the processor is shown in Fig. 4. The processor acts as a proxy to the processor extender. There are two new components in the architecture:
-```
-var (
- // Registry for registered artifact processors
- Registry = map[string]Processor{}
-)
-```
+1. Remote Processor API - HTTP RESTful API between Harbor and remote processor.
+ - The API itself is defined and maintained by Harbor.
+ - Authentication specifics are out-of-scope, but should be supported using the HTTP ```Authorization``` header.
+2. Remote Processor Extender - Long-running RESTful service that implements the Remote Processor API to extract artifact data.
+ - The extender is deployed outside Harbor Core.
+ - The extender has independent configuration management, and deployment lifecycle.
+
+
+
+
Fig. 4 Design of HTTPProcessor
+
-#### Remote Processor API
-For a remote processor, the functions defined in ```Processor``` interface can be abstract to HTTP service API. By using these API, harbor core can call remote HTTP processor.
+For a remote processor, the functions defined in ```Processor``` interface can be abstract to HTTP service API. By using these APIs, Harbor Core can communicate with remote HTTP processor extender.
```
GET {remote-processor-endpoint}/artifacttype
@@ -63,9 +212,11 @@ POST {remote-processor-endpoint}/abstractmetadata
POST {remote-processor-endpoint}/abstractaddition
```
-```HTTPProcessor``` is a ```Processor``` implement which make harbor have extensibility to let users use remote HTTP service process their user defined artifacts by API defined above.
+#### `HTTPProcessor`
-```
+`HTTPProcessor` makes harbor more extensible to allow users using their own processor extender to process the custom artifacts. The `HTTPProcessor` acts as a proxy to the extender. The pseudo code is here.
+
+```go
type HTTPProcessor struct {
MediaType string
ProcessorURL string
@@ -101,44 +252,52 @@ func (h *HTTPProcessor) AbstractAddition(ctx context.Context, artifact *artifact
}
```
-#### Register
-Harbor now using ```app.conf``` to set core config. The configuration info is about core service configuration used for beego. So we can use another configration file just for processor configration info.
-Considering defining a specific type of artifact is not frequent behaviour, there is no need for harbor to expose a API for remote processor to register. So it is a simple way to use a yaml file named ```processor.yaml``` mount in core service to register ```processor``` info when core service start.
-
-```
-Processors:
-- ProcessorUrl: "http://{processor-service-IP}:port"
- ArtifactMediaType: "{media-type-string}"
-```
-
-#### Artifact Data Access
-Refer to [Artifact Data Access](https://github.com/goharbor/community/blob/master/proposals/pluggable-image-vulnerability-scanning_proposal.md#artifact-data-access), there are same problems for remote processor extracting artifact data possibly.
-
-It is possible that when remote processor extracting artifact data, the remote processor still need to retrive data from harbor using the Docker Registry v2 API exposed by Harbor. So remote processor need credentials provided by harbor when API provided by remote processor called by harbor.
+The workflow of pushing a custom artifact to Harbor with the help of `HTTPProcessor` is shown in Fig. 5. The Harbor works as a proxy to the registry when the user uploads the content layers and config layer. Harbor ensures that the repository exists. Then Harbor puts the manifest to the registry. After that, Harbor will check if the artifact by digest exists. In this step, Harbor will use `Processor.AbstractMetatda` in `Abstractor` to abstract the metadata ant keep in the artifact.Artifact model.
-##### Policy Check Interceptor
-Harbor can block image distribution based on severity of vulnerabilities found during scan. Since repote processor is deployed outside the system boundary of harbor, the docker clients used by remote processor are supposed to access the registry through external IP configured by ingress or load balancer. Because of the policy check interceptor, there is a problem of accessing registry via external endpoint which might block pulling.
+
+
+
Fig. 5 Workflow of HTTPProcessor
+
-##### OAuth 2 Bearer Tokens
-Harbor provides a JWT Bearer token to Clair on scan request. The token is generated in OAuth Client Credentials (with client_id and client_secret) flow and then passed directly to Clair in a HTTP POST request to scan a Clair Layer.
+When `HTTPProcessor.AbstractMetadata(ctx context.Context, manifest []byte, artifact *artifact.Artifact) error)` is invoked, it will send a HTTP POST request to the processor extender:
```
-Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkJWM0Q6MkFWWjpVQjVaOktJQVA6SU5QTDo1RU42Ok40SjQ6Nk1XTzpEUktFOkJWUUs6M0ZKTDpQT1RMIn0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJCQ0NZOk9VNlo6UUVKNTpXTjJDOjJBVkM6WTdZRDpBM0xZOjQ1VVc6NE9HRDpLQUxMOkNOSjU6NUlVTCIsImF1ZCI6InJlZ2lzdHJ5LmRvY2tlci5jb20iLCJleHAiOjE0MTUzODczMTUsIm5iZiI6MTQxNTM4NzAxNSwiaWF0IjoxNDE1Mzg3MDE1LCJqdGkiOiJ0WUpDTzFjNmNueXk3a0FuMGM3cktQZ2JWMUgxYkZ3cyIsInNjb3BlIjoiamxoYXduOnJlcG9zaXRvcnk6c2FtYWxiYS9teS1hcHA6cHVzaCxwdWxsIGpsaGF3bjpuYW1lc3BhY2U6c2FtYWxiYTpwdWxsIn0.Y3zZSwaZPqy4y9oRBVRImZyv3m_S9XDHF1tWwN7mL52C_IiA73SJkWVNsvNqpJIn5h7A2F8biv_S2ppQ1lgkbw
+POST {remote-processor-endpoint}/abstractmetadata
+{
+ "registry": {
+ // A base URL of the Docker Registry v2 API.
+ "url": "registry:5000",
+ // For example, `Basic: Base64(username:password)`.
+ "authorization": "hsakjh..."
+ },
+ "manifest": "{\"config\":...}",
+ "artifact": artifact.Artifact{}
+}
```
-Clair, on the other hand, is using the token to pull image layers from Harbor registry. It works because Clair is using a standard ```http``` library and sets a ```Authorization``` header programmatically.
-
-In order to enable Scanner Adapters to bypass Policy Check Interceptor, Harbor's authentication service will generate a dedicated JWT access token and hand it over to the underlying Scanner thru Scanner Adapter in a ScanRequest.
+The `manifest` and `artifact` will be sent to the extender to abstract the metadata. If the registry needs Auth, `registry` will be sent, just like Scanner.
-It is reasonable to use the same way for remote processor using bearer tokens to access to the image data from harbor registry.
+When users deal with these built-in artifact types like OCI Image, CNAB or Helm Chart, the workflow **is not affected**, like Fig. 6. For example, the user uploads a Helm Chart to Harbor, we will use Helm Chart processor to abstract the metadata. Thus the design of `HTTPProcessor` is non-invasive to the current design.
-##### Robot Accounts
-Refer to scan job using credentials generated by robot account mechanism, we can use the same way to use the robot account mechanism to generate credentials that work with these common OCI/Docker tooling libraries to provide credentialed access to the image data. The lifecycle of the robot account credentials can be bound to the HTTP request. For every HTTP request call remote processor API, a robot account expired at certain time will be created.Additionally, a modification is needed to ensure that the generated credentials have access to bypass the configured policy checks on the image that normal users are subject to if those checks are configured.
+
+
+
Fig. 6 Workflow of the Build-in Processor
+
+#### Processor Extender
-#### Remote Processor API define
+We have four RESTful APIs provided by the extender.
```
+GET {remote-processor-endpoint}/artifacttype
+GET {remote-processor-endpoint}/additiontypes
+POST {remote-processor-endpoint}/abstractmetadata
+POST {remote-processor-endpoint}/abstractaddition
+```
+
+The data structure used by the extender is shown here:
+
+```go
// Registry represents Registry connection settings.
type Registry struct {
// A base URL of the Docker Registry v2 API exposed by Harbor.
@@ -188,9 +347,10 @@ type AbstractAdditionResponse struct {
}
```
-#### Remote Processor
-A user defined processor need to build a HTTP service which implement HTTP processor API
-```
+
+A processor extender needs to build a HTTP service which provides these four APIs.
+
+```go
func GetArtifactType() *ListAdditionTypesResponse {
return &ListAdditionTypesResponse{}
}
@@ -208,34 +368,73 @@ func AbstractAddition(req *AbstractAdditionRequest) *AbstractAdditionResponse {
}
```
-## Develop Plan
+### Configuration file `processors.yaml`
-There are totally three things we need to do to complete the proposal
-- implement ```HTTPProcessor```
-- register ```HTTPProcessor``` to harbor core
-- authentication problems
+```app.conf``` is used to configure Harbor Core. The configuration info is about core service configuration used for beego. So we can use another configuration file for processor configuration info.
-1. At the first stage, we will implement the ```HTTPProcessor```.
-At this stage, user defined processor will not register to harbor. So if users want to use remote porcessor, they still need to add registeration logic to harbor code and repcompile harbor core. Also, ```HTTPProcessor``` will make HTTP request to remote processor without privide authentication and Harbor external endpoint. So users need to do some work to generate authentication using other user account. Harbor external endpoint should be configured any way. And policy check interceptor can not be bypassed.
-2. At the second stage, registration logic will be added. Users don't need to modify harbor code any more. A remote processor configration file is required to register specific processor to harbor. When harbor core start, it will read the configuration file and register the processor to harbor.
-3. At the final stage, using robot account mechanism to generate credentials will be finished. Harbor external endpoint and authentication will be passed directy in HTTP POST request body. Users don't need to consider about the authentication problem. But still need to find a way to use authentication properly.
+Considering defining a specific type of artifact is not frequent, there is no need for Harbor to expose a API for remote processor to register. It is simple to use a YAML file named ```processor.yaml```, which will be mounted into core service to register ```processor``` info when core service start.
-## Non-Goals
+```yaml
+Processors:
+- ProcessorUrl: "http://{processor-service-IP}:port"
+ ArtifactMediaType: "{media-type-string}"
+```
-[Anything explicitly not covered by the proposed change.]
+The registration will look like the pseudo code here:
-## Rationale
+```go
+Registry = map[string]Processor{}
+Registry[Processors[].ArtifactMediaType] = HTTPProcessor{ProcessorURL: Processors[].ProcessorURL}
+```
-[A discussion of alternate approaches and the trade offs, advantages, and disadvantages of the specified approach.]
+### Artifact Data Access
-## Compatibility
+Refer to [Artifact Data Access](https://github.com/goharbor/community/blob/master/proposals/pluggable-image-vulnerability-scanning_proposal.md#artifact-data-access), there are same problems for remote processor extracting artifact data possibly.
-[A discussion of any compatibility issues that need to be considered]
+It is possible that when remote processor extracts artifact data, the remote processor still need to retrieve data from Harbor using the Docker Registry v2 API exposed by Harbor. So remote processor need credentials provided by Harbor when API provided by remote processor called by Harbor.
-## Implementation
+#### Policy Check Interceptor
+
+Harbor can block image distribution based on severity of vulnerabilities found during scan. Since processor extender is deployed outside the system boundary of harbor, the client used by processor extender is supposed to access the registry through external IP configured by ingress or load balancer. Because of the policy check interceptor, there is a problem of accessing registry via external endpoint which might block pulling.
+
+#### OAuth 2 Bearer Tokens
+
+Harbor provides a JWT Bearer token to Clair in the request. The token is generated in OAuth Client Credentials (with client_id and client_secret) flow and then passed directly to Clair in a HTTP POST request to scan a Clair Layer.
+
+```
+Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkJWM0Q6MkFWWjpVQjVaOktJQVA6SU5QTDo1RU42Ok40SjQ6Nk1XTzpEUktFOkJWUUs6M0ZKTDpQT1RMIn0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJCQ0NZOk9VNlo6UUVKNTpXTjJDOjJBVkM6WTdZRDpBM0xZOjQ1VVc6NE9HRDpLQUxMOkNOSjU6NUlVTCIsImF1ZCI6InJlZ2lzdHJ5LmRvY2tlci5jb20iLCJleHAiOjE0MTUzODczMTUsIm5iZiI6MTQxNTM4NzAxNSwiaWF0IjoxNDE1Mzg3MDE1LCJqdGkiOiJ0WUpDTzFjNmNueXk3a0FuMGM3cktQZ2JWMUgxYkZ3cyIsInNjb3BlIjoiamxoYXduOnJlcG9zaXRvcnk6c2FtYWxiYS9teS1hcHA6cHVzaCxwdWxsIGpsaGF3bjpuYW1lc3BhY2U6c2FtYWxiYTpwdWxsIn0.Y3zZSwaZPqy4y9oRBVRImZyv3m_S9XDHF1tWwN7mL52C_IiA73SJkWVNsvNqpJIn5h7A2F8biv_S2ppQ1lgkbw
+```
+
+Clair, on the other hand, is using the token to pull image layers from Harbor registry. It works because Clair is using a standard ```http``` library and sets a ```Authorization``` header programmatically.
+
+In order to enable Scanner Adapters to bypass Policy Check Interceptor, Harbor's authentication service will generate a dedicated JWT access token and hand it over to the underlying Scanner thru Scanner Adapter in a ScanRequest.
+
+It is reasonable to use the same way for processor extender using bearer tokens to access to the image data from harbor registry.
+
+#### Robot Accounts
+
+Refer to scan job using credentials generated by robot account mechanism, we can use the same way to use the robot account mechanism to generate credentials that work with these common OCI/Docker tooling libraries to provide credentialed access to the image data. The lifecycle of the robot account credentials can be bound to the HTTP request. For every HTTP request call remote processor API, a robot account expired at certain time will be created.Additionally, a modification is needed to ensure that the generated credentials have access to bypass the configured policy checks on the image that normal users are subject to if those checks are configured.
+
+## Development Process
+
+There are totally three things we need to do to complete the proposal:
+
+- Implement ```HTTPProcessor```
+- Register ```HTTPProcessor``` to Harbor Core using `processors.yaml`
+- Implement the mechanism to support Auth.
+
+Thus we propose to have three iterations. Each of them is self-contained and supposed to be merged into Harbor Core.
+
+### First Iteration: HTTPProcessor and Extender without Auth
+
+At this stage, user defined processor will not register to harbor. So if users want to use processor extender, they still need to hard-code some logic to harbor code to register the type with the corresponding processor manually.
+
+Also, ```HTTPProcessor``` will make HTTP request to the extender without providing authentication and Harbor external endpoint. So users need to do some work to generate authentication using other user account. Harbor external endpoint should be configured any way. And policy check interceptor can not be bypassed.
+
+### Second Iteration: Registration
-[A description of the steps in the implementation, who will do them, and when.]
+At the second stage, registration logic will be added. Users don't need to modify harbor code any more. A remote processor configuration file is required to register specific processor to harbor. When harbor core starts, it will read the configuration file and register the processor to harbor.
-## Open issues (if applicable)
+### Third Iteration: Auth in the Processor Extender
-[A discussion of issues relating to this proposal for which the author does not know the solution. This section may be omitted if there are none.]
+At the final stage, using robot account mechanism to generate credentials will be finished. Harbor external endpoint and authentication will be passed directly in HTTP POST request body. Users don't need to worry about the authentication problem. But still need to find a way to use authentication properly.
diff --git a/proposals/images/artifact-processor-extender/arch.png b/proposals/images/artifact-processor-extender/arch.png
new file mode 100644
index 0000000000000000000000000000000000000000..c13ae6ae536a374ec2fdbafa5d2a80c88676bc70
GIT binary patch
literal 76418
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