Elementary Security in Erlang-OTP

Other texts I have reviewed:

– “Thinking in Erlang” – version 0.9 dated January 31st, 2007, by Robert Baruch

– “OTP Design Principles” – version 5.10.4,  http://www.erlang.org/doc/design_principles/users_guide.html 

– “Making reliable distributed systems in the presence of software errors” – final version updated November 2003, by Joe Armstrong, http://www.sics.se/~joe/thesis/armstrong_thesis_2003.pdf

– “Concurrent Programming in ERLANG”, second edition, first part, by Joe Armstrong, Robert Virding, Claes Wikström and Mike Williams, http://www.erlang.org/download/erlang-book-part1.pdf

None of these adopt Security requirements or Security-related design goals, which –considering that some of these texts are “foundational” in character, helps to set the context for the lack of security concerns and direction in the rest of the literature. For the sake of completeness I have to say again that Erlang is a most fascinating programming language with great achievements already in the industry and with a promising future. I cannot but think that the overwhelming emphasis on engineering and performance targets are now a thing of the past and that the Erlang community must be thinking not only about Security but also of other areas where the technology can be improved.

The OTP Design Principles document is an obligatory text for any Erlang developer. Some articles I read in the past underline how important it is to learn the “ins and outs” of OTP to develop successful Erlang-based systems.  This document (of which I reviewed version 5.10.4 as indicated above) is part of the Erlang OTP System Documentation which can be found here:

http://www.erlang.org/doc/pdf/otp-system-documentation.pdf

Obviously, the Design Principles have to be read in the context of the entire documentation. So if we find a lack of Security aspects in “OTP Design Principles” we should then refer to other sections of the materials to find something that can guide our search for Erlang Security.

In fact this search yields two sub-sections of the User documentation, with critical information indeed. I will reproduce these points in full here for the benefit of other students and for future elaboration:

[The following text is from Section 4 (Getting Started with Erlang)  of the User’s Guide, sub-section 4.3.4 (Distributed Programming)]

“Now let’s re-write the ping pong program with "ping" and "pong" on different computers. Before we do this, there are a few things we need to set up to get this to work. The distributed Erlang implementation provides a basic security mechanism to prevent unauthorized access to an Erlang system on another computer (*manual*). Erlang systems which talk to each other must have the same magic cookie. The easiest way to achieve this is by having a file called .erlang.cookie in your home directory on all machines which on which you are going to run Erlang systems communicating with each other (on Windows systems the home directory is the directory where pointed to by the $HOME environment variable – you may need to set this. On Linux or Unix you can safely ignore this and simply create a file called .erlang.cookie in the directory you get to after executing the command cd without any argument). The .erlang.cookie file should contain on line with the same atom. For example on Linux or Unix in the OS shell:

$ cd $ cat > .erlang.cookie this_is_very_secret

$ chmod 400 .erlang.cookie

The chmod above make the .erlang.cookie file accessible only by the owner of the file. This is a requirement. When you start an Erlang system which is going to talk to other Erlang systems, you must give it a name, eg:

$ erl -sname my_name

We will see more details of this later (*manual*). If you want to experiment with distributed Erlang, but you only have one computer to work on, you can start two separate Erlang systems on the same computer but give them different names. Each Erlang system running on a computer is called an Erlang node. (Note: erl –sname assumes that all nodes are in the same IP domain and we can use only the first component of the IP address, if we want to use nodes in different domains we use -nameinstead, but then all IP address must be given in full (*manual*).”

Here we already see the issue pointed to in a previous post, where it became clear that Erlang has an extremely “light” security mechanism (It is true: there are no other inter-process Security arrangements in Erlang as the one described in the fragment above – aside of the potential for encryption, etc. ) In fact the issue that I see here is that Erlang depends completely on the operating system native file permissions to secure the run-time (and development) environments. As a language though, it does not provide native Security mechanisms. It would be great to find that I am wrong on this.

The second relevant text (and there are no more Security-related entries in the documentation), follows below.

[The following text comes from the “Erlang Reference Manual” (Section 5 of the documentation), subsection 5.12.7 (Security).]

Authentication determines which nodes are allowed to communicate with each other. In a network of different Erlang
nodes, it is built into the system at the lowest possible level. Each node has its own magic cookie, which is an Erlang
atom.

“When a nodes tries to connect to another node, the magic cookies are compared. If they do not match, the connected
node rejects the connection.

At start-up, a node has a random atom assigned as its magic cookie and the cookie of other nodes is assumed to
be  nocookie. The first action of the Erlang network authentication server (auth) is then to read a file named
$HOME/.erlang.cookie. If the file does not exist, it is created. The UNIX permissions mode of the file is set
to octal 400 (read-only by user) and its contents are a random string. An atom Cookie is created from the contents
of the file and the cookie of the local node is set to this using erlang:set_cookie(node(), Cookie). This
also makes the local node assume that all other nodes have the same cookie Cookie.

Thus, groups of users with identical cookie files get Erlang nodes which can communicate freely and without
interference from the magic cookie system. Users who want run nodes on separate file systems must make certain that
their cookie files are identical on the different file systems.

For a node Node1 with magic cookie Cookie to be able to connect to, or accept a connection from, another node
Node2with a different cookie  DiffCookie, the function  erlang:set_cookie(Node2, DiffCookie)
must first be called at Node1. Distributed systems with multiple user IDs can be handled in this way.

The default when a connection is established between two nodes, is to immediately connect all other visible nodes as
well. This way, there is always a fully connected network. If there are nodes with different cookies, this method might
be inappropriate and the command line flag -connect_all false must be set, see erl(1). The magic cookie of the local node is retrieved by calling erlang:get_cookie().”

I think that the reader can safely assume that the two sections quoted here give the Erlang student/programmer *everything* one needs to know about the “native” (current) security facilities provided by the language (Erlang) and by the platform (Erlang-OTP).

Section 5.12.8  “Distribution BIFs” (note: a BIF is a built-in function)  lists the Erlang functions that allow programmatic manipulation of the cookies:

erlang:disconnect_node(Node) Forces the disconnection of a node.
erlang:get_cookie() Returns the magic cookie of the current node.
is_alive() Returns true if the runtime system is a node and can connect to other nodes, false otherwise.
monitor_node(Node, true|false) Monitor the status of Node. A message{nodedown, Node} is received if the connection to it is lost.
node() Returns the name of the current node. Allowed in guards.
node(Arg) Returns the node where Arg, a pid, reference, or port, is located.
nodes() Returns a list of all visible nodes this node is connected to.
nodes(Arg) Depending on Arg, this function can return a list not only of visible nodes, but also hidden nodes and previously known nodes, etc.
set_cookie(Node, Cookie) Sets the magic cookie used when connecting to Node. If Node is the current node, Cookie will be used when connecting to all new nodes.
spawn[_link|_opt](Node, Fun) Creates a process at a remote node.
spawn[_link|opt](Node, Module, FunctionName, Args) Creates a process at a remote node.

In consequence, due to the “thin” and “dependent” nature of Security the Erlang-OTP environment these functions become on the one a key target for Security design requirements and for application development governance.

Overall the aspects described above also underline the importance of providing Erlang with better Security capabilities.

(Source: the top-level page for the Erlang documentation  is here: http://www.erlang.org/doc/index.html )