diff --git a/SECURITY b/SECURITY index a2a4fdf1..fce69836 100644 --- a/SECURITY +++ b/SECURITY @@ -1,106 +1,88 @@ Security Design of corosync The corosync project intends to mitigate the following threats: 1. forged group messaging messages which are intended to fault the corosync executive 2. forged group messaging messages which are intended to fault applications using corosync apis 3. monitoring of network data to capture sensitive information The corosync project does not intend to mitigate the following threats: 1. physical access to the hardware which could expose the private key 2. privledged access to the operating system which could expose the private key or be used to inject errors into the corosync executive. 3. library user creates requests which are intended to fault the corosync executive The corosync project mitigates the threats using two mechanisms: 1. Authentication 2. Secrecy Library Interface ----------------- The corosync executive authenticates every library user. The library is only allowed to access services if it's GID is corosync or 0. Unauthorized library users are rejected. The corosync group is a trusted group. If the administrator doesn't trust the application, it should not be added to the group! Any member of the corosync group could potentially send a malformed request to the executive and cause it to fault. Group Messaging Interface ------------------------- Group messaging uses UDP/IP to communicate with other corosync executives using messages. It is possible without authentication of every packet that an attacker could forge messages. These forged messages could fault the corosync executive distributed state machines. It would also be possible to corrupt end applications by forging changes. Since messages are sent using UDP/IP it would be possible to snoop those messages and rebuild sensitive data. To solve these problems, the group messaging interface uses two new interfaces interal to it's implementation: 1. encrypt_and_sign - encrypts and signs a message securely 2. authenticate_and_decrypt - authenticates and decrypts a message securely When the executive wants to send a message over the network, it uses encrypt_and_sign to prepare the message to be sent. When the executive wants to receive a message from the network, it uses authenticate_and_decrypt to verify the message is valid and decrypt it. Corosync uses AES256/SHA-1 which from the Mozilla Network Security Services (libnss) library. The internal functions utilize the following algorithms: sha1 - hash algorithm secure for using with hmac hmac - produces a 16 byte digest from any length input Every message starts with a struct security { unsigned char digest[20]; A one way hash digest unsigned char salt[16]; A securely generated random number } USING LIBNSS ------------ When corosync is started up libnss is initialised, the private key is read into memory and stored for later use by the code. When a message is sent (encrypt_and_sign): ------------------------------------------ - The message is encrypted using AES. - A digest of that message is then created using SHA256 and based on the private key. - the message is then transmitted. When a message is received (decrypt_and_authenticate): - A Digest of the encrypted message is created using the private key - That digest is compared to the one in the message security_header - If they do not match the packet is rejected - If they do match then the message is decrypted using the private key. - The message is processed. - -Compatibility -------------- - -The encryption type can be changed at runtime with a single command: - -# corosync-cfgtool -c0 - -(0 for nss) - -This will tell all cluster nodes to start using libnss encryption. Note that -it is possible to upgrade node individially by setting the encryption type in -corosync.conf. The last byte of the packet indicates the decryption algorithm -that the receiver should use. - -Once all nodes are using libnss encryption, the option should be set in -in corosync.conf so that it takes effect at the next system reboot. - Comments welcome mailto:discuss@corosync.org diff --git a/man/corosync-cfgtool.8 b/man/corosync-cfgtool.8 index 49b921b6..f3c9784f 100644 --- a/man/corosync-cfgtool.8 +++ b/man/corosync-cfgtool.8 @@ -1,80 +1,77 @@ .\" .\" * Copyright (C) 2010 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Angus Salkeld .\" * .\" * This software licensed under BSD license, the text of which follows: .\" * .\" * Redistribution and use in source and binary forms, with or without .\" * modification, are permitted provided that the following conditions are met: .\" * .\" * - Redistributions of source code must retain the above copyright notice, .\" * this list of conditions and the following disclaimer. .\" * - Redistributions in binary form must reproduce the above copyright notice, .\" * this list of conditions and the following disclaimer in the documentation .\" * and/or other materials provided with the distribution. .\" * - Neither the name of the MontaVista Software, Inc. nor the names of its .\" * contributors may be used to endorse or promote products derived from this .\" * software without specific prior written permission. .\" * .\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE .\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" * THE POSSIBILITY OF SUCH DAMAGE. .\" */ .TH "COROSYNC-CFGTOOL" "8" "2010-05-30" "" "" .SH "NAME" corosync-cfgtool \- An administrative tool for corosync. .SH "SYNOPSIS" .B corosync\-cfgtool [\-i] [IP_address] [\-s] [\-r] [\-l] [\-u] [\-H] [service_name] [\-v] [version] [\-k] [nodeid] [\-a] [nodeid] .SH "DESCRIPTION" .B corosync\-cfgtool A tool for displaying and configuring active parameters within corosync. .SH "OPTIONS" .TP .B -h Print basic usage. .TP .B -i Finds only information about the specified interface IP address. .TP .B -s Displays the status of the current rings on this node. If any interfaces are faulty, 1 is returned by the binary. If all interfaces are active 0 is returned to the shell. .TP .B -r Reset redundant ring state cluster wide after a fault to re-enable redundant ring operation. .TP .B -l Load a service identified by "service_name". .TP .B -u Unload a service identified by "service_name". .TP .B -a Display the IP address(es) of a node. .TP -.B -c -Set the cryptography mode of cluster communications. -.TP .B -k Kill a node identified by node id. .TP .B -H Shutdown corosync cleanly on this node. .SH "SEE ALSO" .BR corosync_overview (8), .SH "AUTHOR" Angus Salkeld .PP diff --git a/tools/corosync-cfgtool.c b/tools/corosync-cfgtool.c index 78e4bbba..dff3d76d 100644 --- a/tools/corosync-cfgtool.c +++ b/tools/corosync-cfgtool.c @@ -1,285 +1,262 @@ /* * Copyright (c) 2006-2012 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int ringstatusget_do (char *interface_name) { cs_error_t result; corosync_cfg_handle_t handle; unsigned int interface_count; char **interface_names; char **interface_status; unsigned int i; unsigned int nodeid; int rc = 0; printf ("Printing ring status.\n"); result = corosync_cfg_initialize (&handle, NULL); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } result = corosync_cfg_local_get(handle, &nodeid); if (result != CS_OK) { printf ("Could not get the local node id, the error is: %d\n", result); } else { printf ("Local node ID %d\n", nodeid); } result = corosync_cfg_ring_status_get (handle, &interface_names, &interface_status, &interface_count); if (result != CS_OK) { printf ("Could not get the ring status, the error is: %d\n", result); } else { for (i = 0; i < interface_count; i++) { if ( (interface_name && (interface_name[0]=='\0' || strcasecmp (interface_name, interface_names[i]) == 0)) || !interface_name ) { printf ("RING ID %d\n", i); printf ("\tid\t= %s\n", interface_names[i]); printf ("\tstatus\t= %s\n", interface_status[i]); if (strstr(interface_status[i], "FAULTY")) { rc = 1; } } } } (void)corosync_cfg_finalize (handle); return rc; } static void ringreenable_do (void) { cs_error_t result; corosync_cfg_handle_t handle; printf ("Re-enabling all failed rings.\n"); result = corosync_cfg_initialize (&handle, NULL); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } result = corosync_cfg_ring_reenable (handle); if (result != CS_OK) { printf ("Could not reenable ring error %d\n", result); } (void)corosync_cfg_finalize (handle); } static void shutdown_do(void) { cs_error_t result; corosync_cfg_handle_t handle; corosync_cfg_callbacks_t callbacks; callbacks.corosync_cfg_shutdown_callback = NULL; result = corosync_cfg_initialize (&handle, &callbacks); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } printf ("Shutting down corosync\n"); result = corosync_cfg_try_shutdown (handle, COROSYNC_CFG_SHUTDOWN_FLAG_REQUEST); if (result != CS_OK) { printf ("Could not shutdown (error = %d)\n", result); } (void)corosync_cfg_finalize (handle); } static void showaddrs_do(int nodeid) { cs_error_t result; corosync_cfg_handle_t handle; corosync_cfg_callbacks_t callbacks; int numaddrs; int i; corosync_cfg_node_address_t addrs[INTERFACE_MAX]; result = corosync_cfg_initialize (&handle, &callbacks); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } if (corosync_cfg_get_node_addrs(handle, nodeid, INTERFACE_MAX, &numaddrs, addrs) == CS_OK) { for (i=0; iss_family == AF_INET6) saddr = &sin6->sin6_addr; else saddr = &sin->sin_addr; inet_ntop(ss->ss_family, saddr, buf, sizeof(buf)); if (i != 0) { printf(" "); } printf("%s", buf); } printf("\n"); } (void)corosync_cfg_finalize (handle); } -static void crypto_do(unsigned int type) -{ - cs_error_t result; - corosync_cfg_handle_t handle; - - printf ("Setting crypto to mode %d\n", type); - result = corosync_cfg_initialize (&handle, NULL); - if (result != CS_OK) { - printf ("Could not initialize corosync configuration API error %d\n", result); - exit (1); - } - result = corosync_cfg_crypto_set (handle, type); - if (result != CS_OK) { - printf ("Could not set crypto mode (error = %d)\n", result); - } - (void)corosync_cfg_finalize (handle); - -} - static void killnode_do(unsigned int nodeid) { cs_error_t result; corosync_cfg_handle_t handle; printf ("Killing node %d\n", nodeid); result = corosync_cfg_initialize (&handle, NULL); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } result = corosync_cfg_kill_node (handle, nodeid, "Killed by corosync-cfgtool"); if (result != CS_OK) { printf ("Could not kill node (error = %d)\n", result); } (void)corosync_cfg_finalize (handle); } static void usage_do (void) { printf ("corosync-cfgtool [-i ] -s] [-r] [-H] [service_name] [-k] [nodeid] [-a] [nodeid]\n\n"); printf ("A tool for displaying and configuring active parameters within corosync.\n"); printf ("options:\n"); printf ("\t-s\tDisplays the status of the current rings on this node.\n"); printf ("\t-r\tReset redundant ring state cluster wide after a fault to\n"); printf ("\t\tre-enable redundant ring operation.\n"); printf ("\t-a\tDisplay the IP address(es) of a node\n"); - printf ("\t-c\tSet the cryptography mode of cluster communications\n"); printf ("\t-k\tKill a node identified by node id.\n"); printf ("\t-H\tShutdown corosync cleanly on this node.\n"); } int main (int argc, char *argv[]) { - const char *options = "i:srk:a:c:hH"; + const char *options = "i:srk:a:hH"; int opt; unsigned int nodeid; char interface_name[128] = ""; int rc=0; if (argc == 1) { usage_do (); } while ( (opt = getopt(argc, argv, options)) != -1 ) { switch (opt) { case 'i': strncpy(interface_name, optarg, sizeof(interface_name)); break; case 's': rc = ringstatusget_do (interface_name); break; case 'r': ringreenable_do (); break; case 'k': nodeid = atoi (optarg); killnode_do(nodeid); break; case 'H': shutdown_do(); break; case 'a': showaddrs_do( atoi(optarg) ); break; - case 'c': - crypto_do( atoi(optarg) ); - break; case 'h': usage_do(); break; } } return (rc); }