mardi 24 mars 2015

Password-less SSH root access

So I had to configure password-less SSH access between a master machine and a slave one:

1. Create an SSH key pair on the master machine
root@master-machine$ ssh-keygen 

2. Create an SSH key pair on the slave machine,
root@slave-machine$ ssh-keygen

To copy the public key to the remote machine we need a root access, however by default password-based SSH access as root is not allowed

3. On the slave machine: sudo passwd.
3.1. set a password for root (if not already set)
3.2. edit /etc/ssh/sshd_config (not /etc/ssh/ssh_config) to change PermitRootLogin without-password to PermitRootLogin yes.
3.3. restart SSH deamon with service ssh restart, if in an ssh session service ssh reload.

4. Copy master's root public key to the authorized keys in the slave machine
root@master-machine$ ssh-copy-id -i root@slave-machine

Disable password-based SSH access for root:
5. On the slave machine, edit /etc/ssh/sshd_config to change PermitRootLogin yes to PermitRootLogin without-password.

6. Now you can ssh as root from the master to the slave machine without password:
root@master-machine$ ssh root@slave-machine

For more details on SSH keys, check link.

vendredi 20 mars 2015

Exposing services to CF applications

Service Broker API

The Service Broker (SB) API (full documentation) enables service providers to expose there offers to applications running on Cloud Foundry (CF). Implementing this contract, allows the CF Cloud Controller (CC) to communicate with the service provider in order to:
  1. Catalog Management: register the offering catalog (e.g. different service plans), 
  2. Provisioning: create/delete a service instance (e.g. create a new MongoDB collection),
  3. Binding: connect/deconnect a CF application to a provisioned service instance.
For each of these possible actions, there an endpoint defined in the Service Broker contract.

1. Catalog Management
The Service Broker (full documentation) should expose an endpoint for catalog management that provides information on the service itself in a JSON format, the different plans (e.g. free or not) that can be consumed by applications, some meta-data that describe the service.

# The Cloud Controller sends the following request
GET http://broker-url/v2/catalog
# The Service Broker may reply as follows
< HTTP/1.1 200 OK
< Content-Type: application/json;charset=UTF-8
...
{
  • services:
    [
    • {
      • planUpdatablefalse,
      • id"a unique service identifier",
      • name"service name",
      • description"service description",
      • bindabletrue,
      • plan_updateablefalse,
      • plans:
        [
        • {
          • id"a unique plan id",
          • name"plan name",
          • description"plan description",
          • metadata: { },
          • freefalse
          }
        ],
      • tags: [ ],
      • metadata: { },
      • requires: [ ],
      • dashboard_clientnull
      }
    ]
}

2. Provisioning
The provisioning consists of synchronous actions that the Service Broker performs on demand from the CC to create a new or destroy an existing resource for the application. The CC sends PUT message with a designated instance identifier. Once the actions are performed, the Service Broker replies with the service and plan identifiers in a JSON format.

# The Cloud Controller sends the following request
PUT http://broker-url/v2/service_instances/:instance_id
{
  • service_id: "service identifier"
    ,
  • plan_id: "plan identifier"
    ,
  • organization_guid: "ORG identifier"
    ,
  • space_id: "SPACE identifier"
}
# The Service Broker may reply as follows
< HTTP/1.1 201 Created
< Content-Type: application/json;charset=UTF-8
...
{
  • dashboard_url: null
}

A service instance once created can be updated (e.g. upgrading service consumption plan). For this, the same query is sent to the SB with a body containing only the attribute to update:
{
  • plan_id: "new_plan_identifier"
}

3. Binding
Binding allows CF application to connect to a provisioned service instance and to start consuming the offered plan. When the SB receives a binding request from a CC, it replies with a the necessary information (e.g. service url, authentication information, etc.) for the CF application to utilize the offered service.

# The Cloud Controller sends the following request
PUT http://broker-url/v2/service_instances/:instance_id/service_bindings/:binding_id
{
  • service_id"service identifier"
    ,
  • plan_id"plan identifier"
    ,
  • app_guid"application identifier"
}
# The Service Broker may reply as follows
< HTTP/1.1 201 Created
< Content-Type: application/json;charset=UTF-8
...
{
  • credentials:
    {
    • uri"a uri to the service instance",
    • username"username on the service",
    • password"password for the username"
    }
  • syslog_drain_url:
     null
}

For unbinding the application from the service, the SB receives on the same URL a request with a DELETE method.

Note! 
All previous requests from the Cloud Controller to the Service Broker contains the X-Broker-Api-Version HTTP header. It designates the Service Broker API (e.g. 2.4) supported by the Cloud Controller.

Managing Service Brokers

Once the previous endpoints are implemented, the SB can be registered to Cloud Foundry to be exposed to applications with the following command:
$ cf create-service-broker SERVICE_BROKER_NAME USERNAME PASSWORD http://broker-url/

To check if the service broker is successfully implemented
$ cf service-brokers

Other possible management operations are available to update, rename or delete a service borker
$ cf update-service-broker SERVICE_BROKER_NAME USERNAME PASSWORD http://broker-url/
$ cf rename-service-broker SERVICE_BROKER_NAME NEW_SERVICE_BROKER_NAME
$ cf delete-service-broker SERVICE_BROKER_NAME

Once the SB is created in CF database, its plans can be viewed with:
$ cf service-access

By default, the plans are all disabled, pick the service name from the output of the previous command and then:
cf enable-service-access SERVICE_NAME # enable access to service
$ cf marketplace -s SERVICE_NAME # output service plans

Managing Services
Once a service broker is available in the marketplace, an instance of the service can be created:
$ cf create-service SERVICE_NAME SERVICE_PLAN SERVICE_INSTANCE_NAME
Then service instances can be seen with:
$ cf services

Connecting service to application
To be able to connect an application to a service (running on a different network) and communicate with it, a route should be added through the definition of a Security group. Security groups allows you to control the outbound traffic of a CF app
cf create-security-group my_security_settings security.json

The content of security.json is as follows
[
  {
    "protocol": "tcp",
    "destination": "192.168.2.0/24",
    "ports":"80"
  }
]

Then, binding to a service instance should be performed as follows:
$ cf bind-service APP_NAME SERVICE_INSTANCE_NAME
Now, the application running on CF can access service instances through the credentials available from the environment variable VCAP_SERVICES.

Resources
  • Managed services in CloudFoundry - link
  • CloudFoundry and Apache Brooklyn for automating PaaS with a Service Broker - link
  • Leveraging Riak with CloudFoundry - link



mercredi 11 mars 2015

Pushing applications to CloudFoundry the Java way

CloudFondry provides a Java API that can be used to do anything just as the CLI. Follows are the steps that shows how to connect and publish an application to CF using Java code:

1. Skip SSL validation
You may have to skip SSL validation to avoid sun.security.validator.ValidatorException:
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
  public void checkClientTrusted(X509Certificate[] xcs, String string) {
  }
  public void checkServerTrusted(X509Certificate[] xcs, String string) {
  }
  public X509Certificate[] getAcceptedIssuers() {
    return null;
  }
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLContext.setDefault(ctx);

2. Connect to CloudFoundry
Connect to the CloudFoundry API endpoint (e.g. https://api.run.pivotal.io) and authenticatewith your credentials:
String user = "admin";
String password = "admin";
String target = "https://api.10.244.0.34.xip.io";
CloudCredentials credentials = new CloudCredentials(user, password);
HttpProxyConfiguration proxy = new HttpProxyConfiguration("proxy_hostname", proxy_port);
CloudFoundryClientclient = new CloudFoundryClient(credentials, target, org, space, proxy);

3. Create an application
String appName = "my-app";
List urls = Arrays.asList("my-app.10.244.0.34.xip.io");
Staging staging = new Staging(null, "app_buildpack_git_repo");
client.createApplication(appName, staging, disk, mem, urls, Collections. emptyList());

4. Push the application
ZipFile file = new ZipFile(new File("path_to_app_archive_file"));
ApplicationArchive archive = new ZipApplicationArchive(file);
client.uploadApplication(appName, archive);

5. Check the application state
StartingInfo startingInfo = client.startApplication(appName);
System.out.println("Starting application: %s on %s", appName, startingInfo.getStagingFile());
CloudApplication application : client.getApplications()
System.out.printf("  %s (%s)%n", application.getName(), application.getState());

6. Disconnect from CloudFoundry
client.logout();