fabric8io / docker-maven-plugin

Maven plugin for running and creating Docker images
https://dmp.fabric8.io
Apache License 2.0
1.88k stars 644 forks source link

support for swarm mode service creation and updates #769

Open kevtainer opened 7 years ago

kevtainer commented 7 years ago

Description

Add support for connecting to swarm manager nodes and UCP and create/update services.

Roadmap

  1. Update security / ssl cert handling to support the host:port used by Docker EE UCP (tcp://manager-node:443), ECDSA certificates. I've solved this issue, but need to figure out how to keep support for RSA key pair. Eg:
KeyPair pair = new org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter().getKeyPair((org.bouncycastle.openssl.PEMKeyPair)readObject);

if (pair instanceof KeyPair) {
  BCECPrivateKey privateKey = (BCECPrivateKey) pair.getPrivate();
  ECPrivateKeySpec keySpec = new ECPrivateKeySpec(privateKey.getD(), privateKey.getParams());
  return KeyFactory.getInstance("ECDSA").generatePrivate(keySpec);
}
  1. Determine the impact of updating the minimum API to version 1.20 as required by the server.
  2. Add mojos for the commands and parameters available in docker service create and docker service update. (this is the bulk of the work).
rhuss commented 7 years ago

Thanks a lot for the idea and the task breakdown!

However, before we start to think of the technical realisation I'd like to go a step back and learn about your use case:

gesellix commented 7 years ago

Regardless of Docker swarm mode, the support for ECDSA encoded certs seems to be a relevant feature. I had a similar issue when clients wanted to access UCP, but I suppose the issue isn't specific to UCP or even Docker swarm mode.

So, to give input to @kcrawley's question how to keep RSA key pairs support: one simply can delegate the PrivateKey generation to the JcaPEMKeyConverter like this (example from https://github.com/docker-client/docker-engine/blob/1422cfb5d83b48e3120b085a22747fd9ebdef0e1/engine/src/main/groovy/de/gesellix/docker/ssl/KeyStoreUtil.groovy#L54):


    static PrivateKey loadPrivateKey(String keyPath) throws IOException, GeneralSecurityException {
        PEMParser parser = new PEMParser(new BufferedReader(new FileReader(keyPath)))
        def parsedObject = parser.readObject()
        if (parsedObject instanceof PEMKeyPair) {
            PEMKeyPair keyPair = (PEMKeyPair) parsedObject
            return generatePrivateKey(keyPair.getPrivateKeyInfo())
        }
        else if (parsedObject instanceof PrivateKeyInfo) {
            return generatePrivateKey((PrivateKeyInfo) parsedObject)
        }
        throw new GeneralSecurityException("Cannot generate private key from file: " + keyPath)
    }

    static PrivateKey generatePrivateKey(PrivateKeyInfo keyInfo) throws IOException, NoSuchAlgorithmException,
                                                                        InvalidKeySpecException {
        try {
            return new JcaPEMKeyConverter().getPrivateKey(keyInfo)
        }
        catch (InvalidKeySpecException e) {
            log.error("couldn't create private key for asn1oid '${keyInfo.getPrivateKeyAlgorithm().algorithm.id}'", e)
            throw e
        }
    }

In other words: I suggest to implement task 1. as described by @kcrawley - if you like I can submit a PR.

rhuss commented 7 years ago

Actually we do something similar in the KeyStoreUtil class, however for PKCS8 encoded certs. This came in with PR https://github.com/fabric8io/docker-maven-plugin/pull/730

As I'm not that deep in SSL and don't know (yet) the difference between PKCS8 and ECDSA encoded certs, I'm not sure how to combine both approaches. (e.g. can the encoding be detected during runtime ?

Any PR is highly appreciated, as I'm quite a bit work loaded these days.

gesellix commented 7 years ago

can the encoding be detected during runtime?

Yes, that's possible via ASN.1 object identifiers and that's exactly what JcaPEMKeyConverter can encapsulate for us.

I'll look into a PR soonish.

rhuss commented 7 years ago

@gesellix thanks !

josephtaylor commented 6 years ago

I think the main use case we have for this is for projects that are designed to be run as a replicated service in swarm. It would be nice to be able to test issues that only crop up in a replicated scenario locally by being able to deploy multiple instances of the container to a local swarm. Of course we can always cook up a docker-compose file for such scenarios and use the CLI, but it'd be awesome to be able to do it with ./mvnw docker:start