Cfengine configuration directory

Security of remote file transfer in cfengine 2

Relevant classes: any

Cfengine employs strong authentication and encryption methods, based on the OpenSSL library.
  • Version 1 of cfengine uses symmetric authentication keys and 3DES encryption.
  • Version 2 uses an implementation of RSA and Blowfish algorithms.
Two things are important to understand about cfengine's version 2 secure copy mechanism
  • Cfengine secure copy is not based on SSL/TLS (although it shares some of the lower level libraries). SSL is not appropriate for a system administration tool like cfengine, because it uses a trust model based on a Trusted Third Party, (as the web uses companies such as Verisign). This implies a centralization of authority that is inappropriate for cfengine's security model.
  • Cfengine does not use ssh. The ssh protocol is not directly appropriate for a system management tool, because it provides only unilateral authentication of user to server. Cfengine authenticates these parties mutually, i.e. user to server, and server to user. Moreover, ssh requires a user to manually accept a key on trust, when the public keys are unknown to the parties, whereas cfengine works non-interactively. SSh uses the notion of binding to a trusted port, to confirm privileged user identity. Cfengine does not make this assumption.

    Apart from these differences, cfengine's authentication and encryption works very like that of the secure shell ssh.

  • Version 2 secure copy is different from version secure copy. In order to upgrade, you will need to temporarily switch off any secured items.
Version 1 of cfengine used symmetric, secret key authentication. Cfengine 2 uses public-private key pairs.
  1. Root generates a key pair on each host
    everyhost# ./cfkey
    Initializing and looking for entropy...
    Making a key pair for cfengine, please wait, this could take a minute...
    Writing private key to /var/cfengine/ppkeys/localhost.priv
    Writing public key to /var/cfengine/ppkeys/localhost.pub
    
    It is recommended that you run the cfenvd daemon in order to generate the keys. This generates sufficient random entropy as a basis for generating the public/private keys automatically. If insufficient entropy can be accumulated, the key generation algorithm fails with message "PRNG not seeded".
  2. Each host needs to know the other public keys of other hosts it needs to talk to. These keys are stored, one per IP-address, as files, like this:
    daneel# ls /var/cfengine/ppkeys/
    root-128.39.74.16.pub  
    mark-128.39.74.43.pub  
    root-128.39.89.10.pub  
    localhost.priv  
    localhost.pub
    
    This exchange of keys can be performed manually, or automatically. This brings up thge issue of trust. In order to accept a key from another host, you have to tell cfengine that you are willing to accept a key on trust. Your trust is needed only once. Once a public key is transferred to a host, it places all of its trust in that key, and ceases to trust the host which it came from. Thus, if a key should be changed, or corrupted, or forged, cfengine will not grant access to the holder of such a key. Public keys need to be removed manually, they can never be renegotiated without manual intervention.

    Key trust is specified in two ways:

    1. Client's trust of server's key is specified in cfagent.conf, or update.conf, by trustkey=true
      copy:
      
       /sourcefile dest=destinationfile server=trustedhost trustkey=true
      
      This means, the first key which the client receives from the server, will be trusted as that server's public key.
    2. Server's trust of a client key is specified in the cfservd.conf file by the TrustKeysFrom access control list. It is based on IP numbers. e.g.
      control:
      
        TrustKeysFrom = ( 192.0.2.11  192.0.2.12 192.0.4 )
      
      
      which grants trust to two hosts and a subnet.
  3. The secure=true/false switch is removed, to mark a change in the security policy. It is replaced by the following related switches
    
    server=hostname
    
    type=checksum        Use an MD5 checksum to determine whether a file needs updating
    
    encrypt=true/false   turn on encryption (requires strong authentication) for this transfer
    trustkey=true/false  accept a key on trust from this server
    
    verify=true/false    Verify the integrity of a transmitted file before installing it
    
    
    
    In cfengine 1, these options were tied together. If "secure=true" was used, it implied "type=checksum", "encrypt=true". It is now possible to choose a different (computationally cheaper) update policy, and still use encryption. Also, a compulsory verification was used in cfengine 1. This is now also optional, and can be applied to any transfer, encrypted or not.
  4. Once identity is established, the client decides a random session key, and Blowfish encryption is used to further communication.

Note on compatibility and upgrading (a19 onwards)

The use of a new encryption scheme means that, the new cfengine client will not talk to version 1 servers at all. Older alpha versions of version 2 servers can be contacted, provided they agree to forego the RSA dialogue. If you are trying to deploy a new version, you can use non-encrypted transfer, using
copy:

source dest=destination server=host oldserver=true
This causes the client to forego the RSA dialogue, and use the older, less efficient file transfer method. This is meant as a temporary convenience, to help users upgrade to version 2.0.0. It is expected that this method will disappear in the future.

Note about security

Please note, that the security of any public key scheme depends entirely on the trust of the keys. If one is to be able to identify true legitimate access to a system, it is important to install a legitimate public key for the connector (client) on the connectee (server) and vice versa. If an attacker can install a key first, then they will win.
Back to documentation