@ -70,6 +70,15 @@ options:
required : false
required : false
default : null
default : null
version_added : " 1.4 "
version_added : " 1.4 "
exclusive :
description :
- Whether to remove all other non - specified keys from the
authorized_keys file . Multiple keys can be specified in a single
key = string value by separating them by newlines .
required : false
choices : [ yes " , " no " ]
default : " no "
version_added : " 1.9 "
description :
description :
- " Adds or removes authorized keys for particular user accounts "
- " Adds or removes authorized keys for particular user accounts "
author : Brad Olson
author : Brad Olson
@ -101,6 +110,9 @@ EXAMPLES = '''
key = " {{ lookup( ' file ' , ' /home/charlie/.ssh/id_rsa.pub ' ) }} "
key = " {{ lookup( ' file ' , ' /home/charlie/.ssh/id_rsa.pub ' ) }} "
key_options = ' no-port-forwarding,host= " 10.0.1.1 " '
key_options = ' no-port-forwarding,host= " 10.0.1.1 " '
# Set up authorized_keys exclusively with one key
- authorized_keys : user = root key = public_keys / doe - jane state = present
exclusive = yes
'''
'''
# Makes sure the public key line is present or absent in the user's .ssh/authorized_keys.
# Makes sure the public key line is present or absent in the user's .ssh/authorized_keys.
@ -336,6 +348,7 @@ def enforce_state(module, params):
manage_dir = params . get ( " manage_dir " , True )
manage_dir = params . get ( " manage_dir " , True )
state = params . get ( " state " , " present " )
state = params . get ( " state " , " present " )
key_options = params . get ( " key_options " , None )
key_options = params . get ( " key_options " , None )
exclusive = params . get ( " exclusive " , False )
error_msg = " Error getting key from: %s "
error_msg = " Error getting key from: %s "
# if the key is a url, request it and use it as key source
# if the key is a url, request it and use it as key source
@ -357,6 +370,10 @@ def enforce_state(module, params):
params [ " keyfile " ] = keyfile ( module , user , do_write , path , manage_dir )
params [ " keyfile " ] = keyfile ( module , user , do_write , path , manage_dir )
existing_keys = readkeys ( module , params [ " keyfile " ] )
existing_keys = readkeys ( module , params [ " keyfile " ] )
# Add a place holder for keys that should exist in the state=present and
# exclusive=true case
keys_to_exist = [ ]
# Check our new keys, if any of them exist we'll continue.
# Check our new keys, if any of them exist we'll continue.
for new_key in key :
for new_key in key :
parsed_new_key = parsekey ( module , new_key )
parsed_new_key = parsekey ( module , new_key )
@ -386,6 +403,7 @@ def enforce_state(module, params):
# handle idempotent state=present
# handle idempotent state=present
if state == " present " :
if state == " present " :
keys_to_exist . append ( parsed_new_key [ 0 ] )
if len ( non_matching_keys ) > 0 :
if len ( non_matching_keys ) > 0 :
for non_matching_key in non_matching_keys :
for non_matching_key in non_matching_keys :
if non_matching_key [ 0 ] in existing_keys :
if non_matching_key [ 0 ] in existing_keys :
@ -402,6 +420,13 @@ def enforce_state(module, params):
del existing_keys [ parsed_new_key [ 0 ] ]
del existing_keys [ parsed_new_key [ 0 ] ]
do_write = True
do_write = True
# remove all other keys to honor exclusive
if state == " present " and exclusive :
to_remove = frozenset ( existing_keys ) . difference ( keys_to_exist )
for key in to_remove :
del existing_keys [ key ]
do_write = True
if do_write :
if do_write :
if module . check_mode :
if module . check_mode :
module . exit_json ( changed = True )
module . exit_json ( changed = True )
@ -424,6 +449,7 @@ def main():
state = dict ( default = ' present ' , choices = [ ' absent ' , ' present ' ] ) ,
state = dict ( default = ' present ' , choices = [ ' absent ' , ' present ' ] ) ,
key_options = dict ( required = False , type = ' str ' ) ,
key_options = dict ( required = False , type = ' str ' ) ,
unique = dict ( default = False , type = ' bool ' ) ,
unique = dict ( default = False , type = ' bool ' ) ,
exclusive = dict ( default = False , type = ' bool ' ) ,
) ,
) ,
supports_check_mode = True
supports_check_mode = True
)
)