[solved] Support for Local Plugins

The current approach to plugins in Drone is problematic, painful, and insecure. The primary issue is that all plugins must be published somewhere that Drone can pull from, and Drone cannot/will not use locally built containers. This approach addresses the ability for multiple organizations to benefit from shared code (one benefit of plugins) but does not address the need for organizations to be able to privately extend the behavior of the system to address needs specific to the organization (another critical benefit plugins should provide.) Additionally because CI workflows are adjacent to some of the more sensitive information in an organization, the inability to use entirely local plugins (I.E. code that cannot change externally) expands the surface area for attack and creates a security risk.

A good example of both the problem and the security risk comes when you consider trying to use a private AWS ECR repository. Drone doesn’t/can’t support AWS ECR (or any other similar repository that requires a separate authentication strategy) out of the box. The proposed solution: use a plugin. This makes sense, but when you consider the security implications of the plugin you have to consider that the plugin will be given highly sensitive access keys with read/write access to the AWS ECR system, as well as URLs for repositories that those keys have access to. The compromise of these keys (especially if connected with the associated URLs) could allow a malicious actor to compromise the containers in almost unlimited ways. In Drone 1.0 and AWS ECR going forward a plugin is discussed for exactly this use case, and davidbyttow, swell guy that he is, posted just such a plugin at https://github.com/davidbyttow/drone-ecr-registry-plugin. Or course using this presents two problems: first, it isn’t published, so we’re back to needing a published plugin, second, if it were published people would be passing some of their organization’s most sensitive keys (those that guard the deployment of their code) through some third party code written by a single unknown and largely anonymous 3rd party, which, if compromised in any way, could compromise their entire ecosystem. If anyone is uncomfortable with that…they can write a plugin…which they will probably want to keep in ECR with all of the other containers they were trying to get at…but then how will they run it?

I think the best solution would be to allow plugins to be declared within the .drone.yml file and referencing either local code or a repository that Drone is able to pull from, such as:

plugins:
- name: Local Foo Plugin
  image: plugin-foo
  dockerfile: "./drone/plugins/foo/Dockerfile"
- name: Remote Bar Plugin
  image: plugin-bar
  repo: "[email protected]:somebody/drone-bar-plugin.git"
  dockerfile: Dockerfile

The above would simply build the indicated container from the specified Dockerfile, and anywhere that plugin-foo/plugin-bar is used it would use this container. This addresses the question of authorship, allows “plugins” that are really non-reusable and non-portable build shims to remain with the code that they build (rather than needlessly separated and published), and allows the source control system backing the whole process to act as the basis for bootstrapping internal plugins and any associated repositories.

The premise of this post, that Drone cannot use local images, is incorrect. Drone only automatically pulls the image if you use the :latest tag (either explicitly or implicitly) or if the image does not exist in the local cache. If you use a versioned image (e.g. plugins/slack:1) and the image exists in the local Docker cache, Drone will always use it. You can also force this behavior by adding pull: never to the a step in your yaml. This is modeled after Kubernetes.

For organizations that have strict security requirements, you always have the option to mirror Docker images in an internal registry and block index.docker.com on the host. Or alternatively, you have the option to create your own Configuration Provider which can be used to validate and even mutate a Yaml file before passing it to Drone, at which time you can apply custom rules and policies.