Friday, May 26, 2017

Securing Apache Storm - part I

This is the first tutorial in a planned three part series on securing Apache Storm. In this post we will look at setting up a simple Storm cluster that authenticates users via Kerberos, and how to run a simple topology on it. Future posts will cover authorization using Apache Ranger. For more information on how to setup Kerberos for Apache Storm, please see the following documentation.

1) Set up a KDC using Apache Kerby

As for other kerberos-related tutorials that I have written on this blog, we will use a github project I wrote that uses Apache Kerby to start up a KDC:
  • bigdata-kerberos-deployment: This project contains some tests which can be used to test kerberos with various big data deployments, such as Apache Hadoop etc.
The KDC is a simple junit test that is available here. To run it just comment out the "org.junit.Ignore" annotation on the test method. It uses Apache Kerby to define the following principals:
  • zookeeper/localhost@storm.apache.org
  • zookeeper-client@storm.apache.org
  • storm/localhost@storm.apache.org
  • storm-client@@storm.apache.org
  • alice@storm.apache.org
Keytabs are created in the "target" folder. Kerby is configured to use a random port to lauch the KDC each time, and it will create a "krb5.conf" file containing the random port number in the target directory.

2) Download and configure Apache Zookeeper

Apache Storm uses Apache Zookeeper to help coordinate the cluster. Download Apache Zookeeper (this tutorial used 3.4.10) and extract it to a local directory. Configure Zookeeper to use Kerberos by adding a new file 'conf/zoo.cfg' with the following properties:
  • dataDir=/tmp/zookeeper
  • clientPort=2181
  • authProvider.1 = org.apache.zookeeper.server.auth.SASLAuthenticationProvider
  • requireClientAuthScheme=sasl 
  • jaasLoginRenew=3600000 
Now create 'conf/zookeeper.jaas' with the following content:

Server {
        com.sun.security.auth.module.Krb5LoginModule required refreshKrb5Config=true useKeyTab=true keyTab="/path.to.kerby.project/target/zookeeper.keytab" storeKey=true principal="zookeeper/localhost";
};

Before launching Zookeeper, we need to point to the JAAS configuration file above and also to the krb5.conf file generated in the Kerby test-case above. Add a new file 'conf/java.env' adding the SERVER_JVMFLAGS property to the classpath with:
  • -Djava.security.auth.login.config=/path.to.zookeeper/conf/zookeeper.jaas
  • -Djava.security.krb5.conf=/path.to.kerby.project/target/krb5.conf".
Start Zookeeper via:
  • bin/zkServer.sh start
3) Download and configure Apache Storm

Now download and extract the Apache Storm distribution (1.1.0 was used in this tutorial). Edit 'conf/storm.yaml' and edit the following properties:
  • For "storm.zookeeper.servers" add "- localhost"
  • nimbus.seeds: ["localhost"]
  • storm.thrift.transport: "org.apache.storm.security.auth.kerberos.KerberosSaslTransportPlugin"
  • java.security.auth.login.config: "/path.to.storm/conf/storm.jaas"
  • storm.zookeeper.superACL: "sasl:storm"
  • nimbus.childopts: "-Djava.security.auth.login.config=/path.to.storm/conf/storm.jaas -Djava.security.krb5.conf=/path.to.kerby.project/target/krb5.conf" 
  • ui.childopts: "-Djava.security.auth.login.config=/path.to.storm/conf/storm.jaas -Djava.security.krb5.conf=/path.to.kerby.project/target/krb5.conf" 
  • supervisor.childopts: "-Djava.security.auth.login.config=/path.to.storm/conf/storm.jaas -Djava.security.krb5.conf=/path.to.kerby.project/target/krb5.conf"
Create a file called 'conf/storm.jaas' with the content:

Client {
    com.sun.security.auth.module.Krb5LoginModule required refreshKrb5Config=true useKeyTab=true keyTab="/path.to.kerby.project/target/zookeeper_client.keytab" storeKey=true principal="zookeeper-client";
};

StormClient {  
    com.sun.security.auth.module.Krb5LoginModule required refreshKrb5Config=true useKeyTab=true keyTab="path.to.kerby.project/target/storm_client.keytab" storeKey=true principal="storm-client" serviceName="storm";
};

StormServer {
    com.sun.security.auth.module.Krb5LoginModule required refreshKrb5Config=true useKeyTab=true keyTab="path.to.kerby.project/target/storm.keytab" storeKey=true principal="storm/localhost@storm.apache.org";
};

'Client' is used to communicate with Zookeeper, 'StormClient' is used by the supervisor nodes and 'StormServer' is used by nimbus. Now start Nimbus and a supervisor node via:
  • bin/storm nimbus
  • bin/storm supervisor
4) Deploy a Topology

As we have the Storm cluster up and running, the next task is to deploy a Topology to it. For this we will need to use another Storm distribution, so extract Storm again to another directory. Edit 'conf/storm.yaml' and edit the following properties:
  • For "storm.zookeeper.servers" add "- localhost"
  • nimbus.seeds: ["localhost"]
  • storm.thrift.transport: "org.apache.storm.security.auth.kerberos.KerberosSaslTransportPlugin"
  • java.security.auth.login.config: "/path.to.storm.client/conf/storm.jaas"
Create a file called 'conf/storm.jaas' with the content:

StormClient {
            com.sun.security.auth.module.Krb5LoginModule required refreshKrb5Config=true useTicketCache=true serviceName="storm";
};

Note that we are not using keytabs here, but instead a ticket cache. Now edit 'conf/storm_env.ini' and add:
  • STORM_JAR_JVM_OPTS:-Djava.security.krb5.conf=/path.to.kerby.project/target/krb5.conf
Now that we have everything set up, it's time to deploy a topology to our cluster. I have a simple Storm topology that wires a WordSpout + WordCounterBolt into a topology that can be used for this in github here. Check this project out from github + build it via "mvn assembly:assembly". We will need a Kerberos ticket store in our ticket cache to deploy the job:
  • export KRB5_CONFIG=/path.to.kerby.project/target/krb5.conf
  • kinit -k -t /path.to.kerby.project/target/alice.keytab alice
Finally we can submit our topology:
  • bin/storm jar /path.to.storm.project/target/bigdata-storm-demo-1.0-jar-with-dependencies.jar  org.apache.coheigea.bigdata.storm.StormMain /path.to.storm.project/target/test-classes/words.txt
If you take a look at the logs in the nimbus distribution you should see that the topology has run correctly, e.g. 'logs/workers-artifacts/mytopology-1-1495813912/6700/worker.log'.

3 comments:

  1. Hi,I am implementing Kerberos with Apache Storm and hence I came across your blog. I have followed similar steps but when starting the UI, I get the following error. I was hoping you could help.

    javax.servlet.ServletException: org.apache.hadoop.security.authentication.client.AuthenticationException: javax.security.auth.login.LoginException: No key to store

    ReplyDelete
  2. This comment has been removed by a blog administrator.

    ReplyDelete
  3. Hi,

    See the next blog entry for how to get the UI working with Kerberos:

    http://coheigea.blogspot.ie/2017/05/securing-apache-storm-part-ii.html

    I didn't see the error you noted. What is the full stacktrace? Are you configuring SSL?

    ReplyDelete