Skip to content
This repository has been archived by the owner on Aug 13, 2020. It is now read-only.

Security

Hakan Englund edited this page Dec 15, 2017 · 22 revisions

Security in Calvin

Supported features

  • Signature verification of applications (of pre-compiled code)
  • Signature verification of actors (of pre-compiled code)
  • Authentication of users using either local file or a RADIUS server
  • Runtime authorization of applications, actors and control interface requests using attribute-based access control
  • Access control post-instantiation of actor
  • Certificate authentication of Distributed Hash Table (DHT) nodes, used as common storage (TODO: add information about this)
  • TLS for transport security for runtime-to-runtime communication as well as for the control interface

Missing features

  • Identity management when migrating an actor into another domain
  • Certificate revocation and re-enrollment

Setting up a security domain

  1. Setup Certificate Authority. The CA is described in Certificate Authority and an example setup given in Example - Configure first runtime.

  2. Sign code is described in Signing applications and actors and an example is given in Example-create codes signer and sign code

  3. Setup authentication server. Explained in Authentication, and an example is given in Example - Configure first runtime.

  4. Setup authorization server. Explained in Authorization, and an example is given in Example - Configure first runtime.

  5. Enable transport layer security as described in Section TLS.

One example of how to setup up two runtimes according to this flow can be found in Example.

Certificate Authority

The authority that issues runtime certificates for the domain. The CA maintains a number of databases: -List of runtimes allowed to operate as authentication servers -List of runtimes allowed to operate as authorization servers -List of enrollment password for runtimes

The Certificate Authority requires a enrollment password appended to a Certificate Signed Request (CSR) for authorization of the CSR. Currently, the CA also always requires TLS (without client authentication) for enrollment requests over the control interface. A enrollment can be queried or set in the CA in the following ways:

Query a password using csmanage:

csmanage ca enrollment_password <domain name> <runtime name>

Alternatively, an enrollment password can be set or queried using the Calvin Control API of the node operating a CA service, see example below. Note that if the authorization policy has restrictions on the control_interface of the runtime serving as an CA server, user credentials for a user allowed to either set or get enrollment password need to be supplied also.

Authentication

Before an application is started, the user is authenticated. If the authentication is successful, subject attributes (e.g. first name and last name) will be returned and included in future authorization requests.

The subject attributes as well as password are stored in the users_db.json file, default location is ~/.security/identity_provider/users.json. Similarly, a groups file is by default stored at ~/.security/identity_provider/groups.json. Below is the content of an example file for usernames/passwords and subject attributes :

{
    "user0": {
        "attributes": {
            "age": "11",
            "last_name": "Andersson",
            "first_name": "Anders",
            "address": "Mobilvagen 1"
         },
         "password": "$pbkdf2-sha256$200000$FAKg1BqDkNI6J2QsRUip1Q$2DfZLQd5WWTQd6808vKGBbmsuX32LzptdYEoEMcpsOU"
     },
     "user1": {
         "attributes": {
            "age": "22",
            "last_name": "Beritsdotter",
            "first_name": "Berit",
            "groups": ["admin", "Ericsson Lund"],
            "address": "Mobilvagen 1"
        },
        "password": "$pbkdf2-sha256$200000$ZQxByDkHQChF6J0zxvi/1w$xBpJQ4IctZ0gx9FiuIV3LrOqpas/7NwJjBSl1K2rgJ8"
     }
}

And a groups file may look like:

{
    "admin": {
        "organization": "Ericsson",
        "organizationalUnit":"IT deparment"
    },
    "Ericsson Lund": {
        "organization": "Ericsson1",
        "location": "Lund",
        "address": "Mobilvagen 1"
    }
}

A user can be added to the users file either by directly inserting the user in the file, or by using the REST interface as described in Authentication database management. If the runtime at startup finds a password in cleartext, the password is hashed and replaced in the users.json file with the correspoding PBKDF2 value.

The credentials are supplied when deploying an application (credentials for multiple domains may be supplied):

$ cscontrol http://localhost:5030 deploy calvin/examples/sample-scripts/test1.calvin --credentials '{"user": "user1", "password": "pass1"}'

Authentication database management

The user and groups database utilized for authentication by the authentication server is managed via a REST interface. The interface is simple, there is no support for adding a single user, the entire file need to be updated.

Fetch users database:

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://localhost:5030/authentication/users_db

Write a new set of users to the data base file:

curl -X PUT -H "Content-Type: application/json" -d '[{"user0":{"username":"user0", "attributes": {"age": "0", "last_name": "Adminsdottir", "first_name": "Admin", "groups": ["admin"], "address": "Mobilvagen 1"}, "password": "pass0"}}]' -i http://localhost:5030/authentication/users_db

Note that if the authorization policy has restrictions on the control_interface of the runtime serving as an authorization server, user credentials for a user allowed to manage the users_db and the groups_db need to be supplied also.

Authorization

The same authorization framework is used to control access to all resources in Calvin. Both for accessing the control interface of runtimes as well as controling who/what/when is allowed to execute actors/applications on which runtimes and which resources they are allowed to use.

Authorization of control interface requests

The access to the control interacce can be controlled on a functional level granularity. The same users accounts are used as when deploying applicaitons. The subject used for requests and polices is "control_interface" along with the name of the function in question, see examples.

Authorization of application/actor access to resources

After the authentication, the application signature is verified and an authorization request is sent if the verification is successful. Similarly, the actor signature is verified before an actor is instantiated and an authorization request is sent after a successful verification. The authorization request includes authenticated subject attributes (e.g. first_name, last_name, application_signer/actor_signer) and the id of the runtime. For actor authorization requests, a list of required runtime functionality is also included in the request.

Request example:

{
    "subject": {
        "first_name": "Tomas",
        "last_name": "Nilsson",
        "actor_signer": "signer"
    },
    "action": {
        "requires": ["runtime", "calvinsys.events.timer"]
    },
    "resource": {
        "node_id": "a77c0687-dce8-496f-8d81-571333be6116"
    }
}

When a runtime is started, the runtime attributes are sent to the authorization server, which means that it is enough to send the runtime id in future authorization requests instead of all the runtime attributes.

Start a runtime and specify attributes for the runtime:

$ csruntime --host localhost --controlport 5030 --port 5031 --attr '{"indexed_public": {"owner": {"organization": "com.ericsson"}, "address": {"country": "SE"}, "node_name": {"organization": "com.ericsson", "name": "testNode"}}}'

Runtime registration example (information sent to the authorization server):

{
    "node_name.name": "testNode",
    "node_name.organization": "com.ericsson",
    "owner.organization": "com.ericsson",
    "address.country": "SE"
}

Policies are used to return an access decision for the authorization request. Possible decisions are permit, deny, indeterminate, not_applicable. If the policy for example denies access to any of the actor requirements, the actor will not be allowed to execute on that particular runtime. It may instead be migrated to another runtime or stay as a shadow actor until a runtime suitable for migration is found.

A policy matches the request if the request attributes match the attributes in the target section of the policy. The attribute values in the policy target can include regular expressions and a list of many alternative values (see policy example below). Policies without target match all requests. If many policies match the request, the policy decisions are combined according to the policy_combining algorithm in the configuration.

A policy has one or many rules where the rule effect is either permit or deny. The rule_combining value (permit_overrides or deny_overrides) determines how the rule decisions are combined to get a policy decision.

A rule may have a target section in the same way as the entire policy to specify for which requests it is valid. The condition section of a rule can be used to specify more advanced conditions for the rule. Attribute values in the request can be compared to values in the policy or other attributes in the request using different functions.

The following options can be used as function for the conditions:

  • equal
  • less_than_or_equal
  • greater_than_or_equal
  • not_equal
  • and
  • or

For and and or, at least two attributes need to be specified as function arguments (the result of another function can be used as argument, see policy example below). The other functions require exactly two attributes as function arguments. Regular expressions and a list of many alternative attribute values may be used. A string that starts with attr: is a reference to the attribute value in the request, e.g. attr:resource:address.country. Missing attributes, i.e. referenced attributes that are not found in the request, are fetched from a Policy Information Point if possible (e.g. the current date in the example below).

Policy example:

{
    "id": "policy1",
    "description": "Security policy for user 'Tomas' or 'Gustav'
                    'Nilsson' with actor signed by 'Ericsson'.",
    "rule_combining": "permit_overrides",
    "target": {
        "subject": {
            "first_name": ["Tomas", "Gustav"],
            "last_name": "Nilsson",
            "actor_signer": "Ericsson"
        }
    },
    "rules": [
        {
            "id": "policy1_rule1",
            "description": "Permit access to 'calvinsys.events.timer',
                            'calvinsys.io.*' and 'runtime' between
                            09:00 and 17:00 if condition is true.",
            "effect": "permit",
            "target": {
                "action": {
                    "requires": ["calvinsys.events.timer", "calvinsys.io.*",
                                 "runtime"]
                }
            },
            "condition": {
                "function": "and",
                "attributes": [
                    {
                        "function": "equal",
                        "attributes": ["attr:resource:address.country",
                                       ["SE", "DK"]]
                    },
                    {
                        "function": "greater_than_or_equal",
                        "attributes": ["attr:environment:current_date",
                                       "2016-03-04"]
                    }
                ]
            },
            "obligations": [
                {
                    "id": "time_range",
                    "attributes": {
                        "start_time": "09:00",
                        "end_time": "17:00"
                    }
                }
            ]
        }
    ]
}

The value of actor_signer or application_signer corresponds to the Common Name (CN) of a X.509 certificate, and only certificates stored in the truststore are applicable. If the value is __unsigned__, applications or actors that are not signed will be permitted.

For the list of actor requirements (requires), runtime is used to denote basic runtime execution access, but without access to specific calvinsys functionality. It is possible to grant access to a particular functionality, e.g. calvinsys.media.camera, or to all the media related functionality, e.g. calvinsys.media.*.

Post-instantiation access control for actors can be used to make it possible to grant access for example only during a certain time period of the day (see obligations in the policy example above). When access is denied, the runtime will automatically try to migrate the actor to another runtime where the actor has permission to run.

When external authorization is used (see configuration settings in Section Security configuration, certificates are needed to verify signed JSON Web Tokens (JWT) that contain the authorization request/response. Another runtime that can act as authorization server must have "accept_external_requests": true in the security configuration. The authorization will only work if both the authorization server runtime and the runtime that sends the authorization request have the certificate of the other runtime in their ~/.calvin/security. If not already locally stored by the runtime, the target certificate is fetched from storage automatically.

Policy management

The Calvin Control API can be used for policy management (create, update, delete policies, etc.).

Note that the the Control API requires that the policies are named according ot the format POLICY_<hash value>.json, e.g., POLICY_60b75549-ee00-4ff4-9c02-223853120b95.json.

Signing applications and actors

Applications, uncompiled as well as compiled actors can be signed using the csmanage tool.

A signature file is created with the name filename.sign.<cert-hash> in the same directory as the file that was signed. The certificate hash is used to find the correct certificate in the truststore folder (signature_trust_store in the configuration, see above), where the certificate name is <cert-hash>.0. See example usage below.

Transport Layer Security

Currently the only transport layer security that is supported is TLS (note that the authentication and authorization frameworks do additionally use object security for tranported objects, currently only integrity protection is used). TLS can be enabled independently on the runtime-to-runtime interface repsectively for the control interface. TLS for runtime-to-runtime communication can be enabled by including the following flag in a calvin configurations file:

{
"security": {
    "runtime_to_runtime_security": "tls"
    }
}

Similarly, TLS for the control interface can be enabled by including the following flag in a calvin configurations file:

{
  "security": {
    "control_interface_security": "tls"
  }
}

The framework assumes that runtime certificates credentials have been created and a certificate has been created by a Certificate Authority, the same certificates are used for transport security as for the secure DHT implementation. All runtimes on the same device share truststore for trusted CAs. The truststore can be found at <path to security_dir>/runtimes/truststore_for_transport/.

Runtime certificates contain both the hostname and the calvin node name in the subjectAltNames section of X509 certificates. The python request package used by the test framework will require that the hostname of the node matches the certificate. Twisted is more flexible, and allows us to during normal operation instead match the certificate with the node name.

Security configuration

This section describes what security configuration that can be made in the Calvin configurations.

By default, all security features are disabled, but this will likely change in future releases. Different features can be enabled by using different configuration flags in a _calvin.conf file.

The security_conf section contains information about authentication and authorization. Details for the security section:

  • certificate_authority -- configuration regarding the domain
    • is_ca -- boolean indicating if runtime shall act as a CA or not.
    • domain_name -- name of the security domain, i.e., CA name, of which the runtime is a part of
    • enrollment_password -- Password from the CA that is used for authorization of the CSR sent from the runtime to the CA runtime. Not needed if a runtime certificate has already been provisioned.
    • ca_control_uri -- The control uri of the runtime running the CA service, used when a runtime starts without a valid certificate.
  • control_interface_security -- Select security transport mechanism for control interface. Currently supported values are ["tls", None].
  • runtime_to_runtime_security -- Select security transport mechanism for protection of application data sent between runtime. Currently supported values are ["tls", None]. TLS is configured to require certificate based client authentication using, i.e., both runtimes communicating need keys and certificates.
  • security_dir -- The directory where to store runtime credentials if other than default, default is ~/.calvin/security.
  • security_conf section:
    • authentication -- configuration of user authentication.
      • procedure -- authentication procedure, currently local, external, and radius are supported.
        • local means that local authentication is used, i.e. usernames, passwords and subject attributes are stored in the file users.json in the identity_provider_path directory on the same machine as the runtime.
        • accept_external_requests -- Only used when procedure is local. Boolean (true/false) indicating if the runtime accepts authorization requests from other runtimes, i.e. can act as authorization server for other runtimes.
        • external means that another runtime acts as authentication server and performs the authentication on behalf of this runtime.
        • radius means using requests to a RADIUS server, which verifies username/password and replies with subject attributes.
      • identity_provider_path -- Only used when procedure is local. The path to the directory with the JSON file containing usernames, passwords and subject attributes.
      • server_uuid -- Only used when procedure is external. The uuid for the runtime that is used as authentication server.
      • server_ip -- Only used when procedure is radius. The IP address of the RADIUS server.
      • secret -- Only used when procedure is radius. The shared secret between the RADIUS client and the RADIUS server.
    • authorization -- configuration of authorization (attribute-based access control).
      • procedure -- authorization procedure, currently local and external are supported.
        • local means that local authorization is used, i.e. policies are stored in JSON files in the policy_storage_path directory on the same machine as the runtime.
        • external means that another runtime act as authorization server and performs the authorization on behalf of this runtime.
      • policy_storage_path -- Only used when procedure is local. The directory where the policy files are stored. Default value: ~/.calvin/security/policies.
      • policy_combining -- Only used when procedure is local. Default value: permit_overrides.
        • permit_overrides means that if multiple policies match the request and at least one of them returns permit, the access decision will be permit.
        • deny_overrides means that if multiple policies match the request and at least one of them returns deny, the access decision will be deny.
      • accept_external_requests -- Only used when procedure is local. Boolean (true/false) indicating if the runtime accepts authorization requests from other runtimes, i.e. can act as authorization server for other runtimes.
      • server_uuid -- Only used when procedure is external. The uuid for the runtime that is used as authorization server.

Example

In the following example, we assume that the an environmental variable "CALVIN_BASE_DIR" has been to the path of the downloaded calvin-base source directly. Below is an example:

$ CALVIN_BASE_DIR=~/calvin-base

Configure first runtime

The first runtime will operate all of the security services for the domain, it will run a CA service, as authentication services as well as and authorization services. So there is a bit of work needed to start up this runtime. However, adding further nodes will be much easier (as described in setting up a second runtime).

In the CALVIN_BASE_DIR, let's create a folder for specific configurations for our first runtime.

$ mkdir $CALVIN_BASE_DIR/node0
$ touch $CALVIN_BASE_DIR/node0/node0_attributes.json
$ touch $CALVIN_BASE_DIR/node0/calvin.conf

Let's first fill the node attribute file (node0_attributes.json) with information about the runtime: Note that these attributes will result in a node name "Ericsson--CA-authserver-authzserver--node0" which we will use later on. This node will act as a Certificate Authority, as the global authorization and authentication server for all runtimes in this domain. This is hence described in the purpose attribute.

{
    "indexed_public":{
        "node_name":{
            "name":"node0",
            "organization":"Ericsson",
            "purpose": "CA-authserver-authzserver"
        }
    }
}

Let us now setup the configuration file for node 0 (i.e., the calvin.conf file). The node will require TLS to be enabled for both runtime-to-runtime communication as well as for the control interface.

{
    "global": {
        "storage_type": "local"
    },
    "security": {
        "certificate_authority": {
            "is_ca": true,
            "domain_name": "Ericsson"
        },
        "runtime_to_runtime_security": "tls",
        "control_interface_security": "tls",
        "security_conf": {
            "comment": "Authorization and Authentication server",
            "authentication": {
                "procedure": "local",
                "identity_provider_path": "~/.calvin/security/identity_provider",
                "accept_external_requests": true
            },
            "authorization": {
                "procedure": "local",
                "policy_storage_path": "~/.calvin/security/policies",
                "accept_external_requests": true
            }
        }
    }
}

Setup CA service

Runtimes configured as CAs can genererate their certificate chains automatically when starting for the first time. However, we need to export the CA root certificate into the truststore of all runtimes, so we will do this manually using the csmanage tool. As we in this example are running all runtimes on the same machine, this is easy (all runtimes on the machine share the same truststore if not otherwise configured).

Create CA and export certificate to runtimes as a trusted root certificate:

$ csmanage ca create Ericsson
$ csmanage ca export Ericsson ~/.calvin/security/runtimes/truststore_for_transport/

OpenSSL and most packages using OpenSSL rely on the truststore folder being structured in a particular way. There is a tool called c_rehash that does this but it is also supported in the csmanage tool for Calvin. It creates symbolic links to the root certificates names as the truncated hash value of the certificate and an additional integer (starting at 0) that is used to differentiate potentially collisions of the truncated certificate hashes.

$csmanage runtime c_rehash CA

The command above will create the file ~/.calvin/security/runtimes/truststore_for_transport/8b391824.0 that is a link pointing to the file ~/.calvin/security/runtimes/truststore_for_transport/Ericsson.pem

Runtimes will only trust other nodes to operate as authentication and authorization server if this is indicated by their certificate, more specifically by incorporating the "authserver" and "authzserver" strings in the CommonName. The CA only accepts requests for such certificates if this has been allowed by whitelists in the CA. So let's create such white lists. Add node0 (which will get the commonName "Ericsson--CA-authserver-authzserver--node0" based on the attributes we chose )to the list of nodes authorized to be authentication servers (~/.calvin/security/Ericsson/allowed_auth_list.json) with the follwing content:

$echo "Ericsson--CA-authserver-authzserver--node0" > ~/.calvin/security/Ericsson/allowed_auth_list.json

Add node0 to the list of nodes authorized to be authorization servers (~/.calvin/security/Ericsson/allowed_authz_list.json) with the follwing content:

$echo "Ericsson--CA-authserver-authzserver--node0" > ~/.calvin/security/Ericsson/allowed_authz_list.json

Configure Authentication service

Create a folder for the user databases

$ mkdir ~/.calvin/security/identity_provider

Create a users_db file (~/.calvin/security/identity_provider/users.json):

$ touch ~/.calvin/security/identity_provider/users.json

Populate the file with the following content:

{
    "user0":{
        "attributes": {
            "age": "0",
            "last_name": "Adminsdottir",
            "first_name": "Admin",
            "address": "Mobilvagen 1",
            "groups":["admin"]
        },
        "password": "pass0"
    },
    "user1":{
        "attributes": {
            "age": "11",
            "last_name": "Andersson",
            "first_name": "Anders",
            "address": "Mobilvagen 1",
            "organization":"Calvin user"
        },
        "password": "pass1"
    }
}

and a groups_db file (~/.calvin/security/identity_provider/groups.json):

$ touch ~/.calvin/security/identity_provider/groups.json

Populate the file with the follwing content:

{
    "admin": {
        "organization": "Ericsson",
        "organizationalUnit": ["IT department"]
    },
    "Ericsson Lund": {
        "organization": "Ericsson",
        "location": "Lund",
        "address": "Mobilvagen 1"
    }
}

Configure Authorization service

Create a folder to store authorization policies in

$ mkdir ~/.calvin/security/policies

Now the authentication server should be properly configured, let's setup up the policies for the authorization server also. Create a first policy giving the Admin user full access to configure the domain via the control interface (~/.calvin/security/policies/policy0.json):

$ touch ~/.calvin/security/policies/policy0.json

Populate the file with the follwing content:

{
    "id": "policy0",
    "description": "Security policy for user0 (Admin) which has full access to the control interface of all runtimes",
    "rule_combining": "permit_overrides",
    "target": {
        "subject": {
            "control_interface": ".*"
        }
    },
    "rules": [
        {
            "id": "policy0_rule0",
            "description": "Give Admin full access to the control interface of testNode0",
            "effect": "permit",
            "target":{
                "subject":{
                    "first_name":["Admin"],
                    "control_interface":".*"
                }
            }
        }
    ]
}

Create a second policy (~/.calvin/security/policies/policy1.json), for user Anders, who's allowed to deploy applications, i.e., we need to grant Anders rights for atleast "handle_deploy" for the control interface. :

$ touch ~/.calvin/security/policies/policy1.json

As mentioned earlier when signing the application and actors, two actors are used in this example:

  • std.CountTimer: requires access to [sys.timer.once, sys.timer.repeating]
  • io.Print: requires access to [io.stdout]

We will also restrict Anders to only deploy applications and actors that are signed by the code signer we created previously, i.e,, EricssonCS

Populate the file with the following content:

{
    "id": "policy1",
    "description": "Security policy for user1 (Anders)",
    "rule_combining": "permit_overrides",
    "target": {
        "subject": {
            "first_name":["Anders"]
        }
    },
    "rules": [
        {
            "id": "policy1_rule0",
            "description": "Control interface",
            "effect": "permit",
            "target": {
                "subject": {
                    "control_interface":["handle_deploy"]
                }
            }
        },{
            "id": "policy1_rule1",
            "description": "Runtime resources",
            "effect": "permit",
            "target": {
                "subject":{
                    "actor_signer": ["EricssonCS"]
                },
                "action": {
                    "requires":["io.stdout", "sys.timer.*"]
                }
            }
        },{
            "id":"policy1_rule2",
            "description":"Application signers",
            "effect":"permit",
            "target":{
                "subject":{
                    "application_signer": ["EricssonCS"]
                }
            }
        }
    ]
}

Create Code Signer and sign code

Now node0 is properly configured. But the authorization policy we just setup only allows applications and actors that are signed by a Code Signer called Ericsson (if code signer is named Ericsson is created using the csmanage tool, it will generate a certificate with organization=Ericsson, and commonName=EricssonCS, the commonName is used by the authorization framework which is why the policy above use EricssonCS), let's create this CS and sign all actors/applications we want to test. Similar to the CA certificate, the CS certificate has to be imported into the truststore used for code signature verification.

$ csmanage cs create Ericsson
$ csmanage cs export Ericsson ~/.calvin/security/runtimes/truststore_for_signing/

Let us once again use the c_rehash tool to create symbolic links for the truststore used for code signature verification.

$csmanage runtime c_rehash CS

The command above will create the file ~/.calvin/security/runtimes/truststore_for_signing/6bf86dba.0 that is a link pointing to the file ~/.calvin/security/runtimes/truststore_for_signing/Ericsson.pem (note that this is not the same Ericsson.pem certificate as used for transport security, the names of the entities are just lazily named the same).

Sign the application we are going to test (test1.calvin), and the actors used by the application (CountTimer.py and Print.py):

$ csmanage cs sign Ericsson $CALVIN_BASE_DIR/calvin/examples/sample-scripts/test1.calvin
$ csmanage cs sign Ericsson $CALVIN_BASE_DIR/calvin/actorstore/systemactors/std/CountTimer.py
$ csmanage cs sign Ericsson $CALVIN_BASE_DIR/calvin/actorstore/systemactors/io/Print.py

Note that these signed actors have to be distributed and used on all runtimes in the domain. However, in this example, all runtimes run from the same repository and on the same machine.

Now start the first runtime

$ cd $CALVIN_BASE_DIR/node0
$ csruntime -n $HOSTNAME -p 5000 -c 5030 --attr-file node0_attributes.json

Setup a second runtime

Open a new terminal, and create a directory for configurations of our second runtime, called node1

$ CALVIN_BASE_DIR=~/calvin-base
$ mkdir $CALVIN_BASE_DIR/node1
$ touch $CALVIN_BASE_DIR/node1/node1_attributes.json
$ touch $CALVIN_BASE_DIR/node1/calvin.conf

Let's set attributes for a second runtime ($CALVIN_BASE_DIR/node1/node1_attributes.json)

{
    "indexed_public":{
        "node_name":{
        "name":"node1",
        "organization":"Ericsson"
        }
    }
}

We need to query or set a certificate enrollment password for node1 at the CA. Note that only the Admin user (i.e., user0 with password pass0) is allowed to do this according to the policy we have set previously. In this example we will use the option to set a chosen certificate enrollment password "abrakadabra123456789" The node name will be needed, this is derived straight forwardly from the attributes set above, but can also be given by csmanage:

$ csmanage runtime get_name --attr-file $CALVIN_BASE_DIR/node1/node1_attributes.json
node_namestart<Ericsson----node1>node_name_stop
$ URL=https://$HOSTNAME:5030/certificate_authority/certificate_enrollment_password/Ericsson----node1
$ curl -X PUT -H "Content-Type: application/json" -d '{"enrollment_password":"abrakadabra123456789"}' $URL -u user0:pass0 --capath ~/.calvin/security/runtimes/truststore_for_transport/

For the configuration file for the second runtime, we will need the host name of runtime 0. The hostname can be found by running the following commonand on the machine where runtime 0 is running:

$ echo $HOSTNAME

The resulting hostname should be set in the below configurations instead of < node0 hostname>. Set the following in configuration file ($CALVIN_BASE_DIR/node1/calvin.conf)

{
    "global": {
        "storage_type": "proxy",
        "storage_proxy":"calvinip://<node0 hostname>:5000"
    },
    "security": {
        "certificate_authority": {
            "ca_control_uri": "https://<node0 hostname>:5030",
            "domain_name": "Ericsson",
            "enrollment_password": "abrakadabra123456789",
        },
        "runtime_to_runtime_security": "tls",
        "control_interface_security": "tls",
        "security_conf": {
            "comment": "Use runtime0 as external Authorization and Authentication server",
            "authentication": {
                "procedure": "external"
            },
            "authorization": {
                "procedure": "external"
            }
        }
    }
}

Now start the second runtime

$ cd $CALVIN_BASE_DIR/node1
$ csruntime -n $HOSTNAME -p 5001 -c 5031 --attr-file node1_attributes.json

Deploy signed application

Open a new terminal, and deploy the signed application as user Anders (i.e., user0)

$ CALVIN_BASE_DIR=~/calvin-base
$ cscontrol --credentials '{"user":"user1","password":"pass1"}' https://$HOSTNAME:5031 deploy $CALVIN_BASE_DIR/calvin/examples/sample-scripts/test1.calvin

Check the console output of node1 and verify that is counting.

After successfull enrollment, a folder structure similar (certificate name will differ) to the example below should be in place. In the example, the follwing security services is running on the same device:

  • Two runtimes are placed on the same device.
  • One of the runtime ("node0")acts as a Certificate Authority for the security domain called "Ericsson".
  • A code signer called "Ericsson" is created on the device.
  • An idenity provider (authentication services) and an authorization server is running on the runtime called "node0".
~/.calvin/security
├── runtimes
│   ├── Ericsson--CA-authserver-authzserver--node0
│   │   ├── mine
│   │   │   └──69ff6db3-e160-429f-9a11-8f5d5d82f5ca.pem
│   │   ├── others
│   │   │   └──815f9e06-3bea-4582-af7a-bcec4d14a1ee.pem
│   │   ├── private
│   │   │   └──private.key
│   │   └── openssl.conf
│   ├── Ericsson----node1
│   │   ├── mine
│   │   │   └──815f9e06-3bea-4582-af7a-bcec4d14a1ee.pem
│   │   ├── others
│   │   │   └──69ff6db3-e160-429f-9a11-8f5d5d82f5ca.pem
│   │   ├── private
│   │   │   └──private.key
│   │   └── openssl.conf
│   ├── truststore_for_signing
│   │   ├── Ericsson.pem
│   │   └── 6bf86dba.0
│   └── truststore_for_transport
│       ├── Ericsson.pem
│       └── 8b391824.0
├── code_signers
│   └── Ericsson
│       ├── new_signed_code (not used)
│       ├── private
│       │   ├── cs.key
│       │   └── cs_password
│       └── cscert.pem  (given name 93d58fef.* when exported)
├── identity_provider
│   ├── groups.json
│   └── users.json
├── policies
│   ├── policy0.json
│   └── policy1.json
└── Ericsson
    ├── certs (not used)
    ├── crl (not used)
    ├── newcerts
    │   ├── 1001.pem  (temporary certificate file for node0)
    │   ├── 1002.pem  (temporary certificate file for node1)
    │   ├── 69ff6db3-e160-429f-9a11-8f5d5d82f5ca.pem  (certificate created for node1)
    │   ├── 815f9e06-3bea-4582-af7a-bcec4d14a1ee.pem  (certificate created for node2)
    ├─── private
    │     ├── ca.key
    │     ├── ca_password
    │     └── enrollment_challenge_db.json
    ├── allowed_auth_list.json    (nodes allowed to operate authentication service)
    ├── allowed_authz_list.json    (nodes allowed to operate authorization service)
    ├── cacert.pem    (given name 6b5516ab.* when exported)
    ├── enrollment_enrollment_db.json
    ├── index.txt   (index of all created certificates)
    ├── index.txt.attr
    ├── openssl.conf
    └── serial  (serial number to be used for next to be created certificate)