Need help copying file from specific host to all targets

I am trying to figure out how to copy a cert file generated on a specific host (ca-server) to the list of hosts defined in the playbook. The scenario is something like this:

  1. using delegate_to go to the ca-server and generate the client cert (stored locally on the ca-server)
  2. copy the client cert to local
  3. push cert file to all targets in the play

using the “standard” modules, copy, fetch, synchronize etc. all seem to want to copy the file from local to the targets or fetch from the targets to local. I do not have direct ssh access from the ca-server to the targets so cannot use “delegate_to” to copy as this appears to execute on the ca-server and tries to connect from there to the targets.

copy: issue here is that it copies from local to the targets unless you define remote_sec as true in which case it is all on the target.
fetch: tries to pull from targets, if delegate_to is used it tries to pull from the targets directly to the delegate
synchronize: requires direct access from ca-server to the targets

The following is the short version of what I am trying to do…

  • hosts: not-the-ca-server
    become_user: root
    become_method: sudo
    tasks:

  • name: Generate the p12 cert

command: “do stuff, execute custom script etc.”
delegate_to: ca-server

  • name: copy the p12 file locally

this is where I am trying to figure out how to grab the file from the ca-server

fetch (or something like this): >
dest=ssl-certs
src=“/foo.p12”

  • name: copy the cert file to the targets
    copy: >
    dest=/etc/ssl/certs/
    src=“ssl-certs/foo.p12”

There may be an obvious answer here as I am pretty new to ansible but I havce bounced this off of a couple of people I know and it stumped them as well…

Thanks for any help.

Gordon

looks fine, if you want to avoid copying the cert to disk you might want to switch to slurp and template to generate the copy.

Are you trying to generate one cert that is then used on all servers or generate individual certs for each server?

It seems that you are saying that you want to...

1) generate a single cert on the ca server
2) copy that to the ansible server
3) copy that cert to all of the other servers

If that is correct wouldn't it be best to have one pair of tasks to do 1 and 2 only on the CA server and 3 on the other servers.

Note that the cert will be different every time this is run so it will never not change. Splitting into two separate sets would allow the cert creation to be run independently from copying it out, and keep the cert push to only changing when the cert changes. An alternative would be to use creates to ensure the cert isn't recreated every time.

If the goal is to have a different cert for every host you should be able to just delegate the cert creation task and the fetch task to the ca server.

Brian, the issue is that it does not work :slight_smile:

let me map it out another way. there is a host that is the certificate authority and certs are generated and signed on this host using a script. this host is pretty locked down and has no direct access to the rest of the infrastructure via SSH. The controller (where the playbook is invoked from) will have access to both the cert server and the targets but the targets and the ca server have no direct access.

So the signed cert gets generated doing this:

  • name: Generate the p12 cert

command: “do stuff, execute custom script etc.”
delegate_to: ca-server

and now I have a cert sitting on the ca server in a file I need to copy to the hosts defined in the playbook. Fetch will pull files from the targets and delegate_to just changes where the fetch gets invoked. What I need to do it copy from the ca-server to local to targets.

Make sense?

so, realistically you are saying that a delegated fetch does not do what is expected but a delegated command does.

My understanding is that delegate effectively changes the target, so fetch with delegate should involve the ansible host pulling the certificate from the ca server. If this is not the case then it seems to be a bug.

My under standing of delegate_to means “run the command you would have run locally on this particular host”, yes? Delegating the command says “run this particular command on this particular host” and a delegated fetch says “run this fetch but run it from this particular host”, I may be totally off here as I only started working with Ansible a few weeks ago but that is the behavior I am seeing.

I would disagree with your summary, but I think you are right...

We have three hosts in the equation. The machine we are running ansible on (ansibleServer) the machine we are performing tasks on (inventoryServer) and a delegate machine (delegateServer)

- task: blah blah blah

would cause ansibleServer to run a task on the inventoryServer

- task: blah blah blah
  delegate_to: delegateServer

should cause ansibleServer to run the task on the delegateServer on behalf of the inventoryServer.

So
- fetch: ...
  delegate_to: delegateServer

SHOULD fetch a file from delegateServer to ansibleServer rather than from inventoryServer.

If not then there is a bug in my opinion.

​incorrect, its
: command i would have run on 'inventory_hostname' run on 'delegate_to'
host instead​

I apologize for the delay in responding to this. I will revalidate this but the fetch+delegate_to appears to pull a file from the inventoryServer to the delegateServer. I will post output as soon as I have it.

So apparently I was doing something wrong. As Adam indicated it should be, it all just works now…

Running a simple case test:

  • hosts: some_host
    become_user: root
    become_method: sudo
    tasks:
  • fetch: >
    dest=/tmp/foo
    fail_on_missing=yes
    src=/tmp/foo.txt
    delegate_to: delegateHost

it indeed pulls the right file from the right place.
Thanks for you help!