IceSSL插件配置

1. IceSSL简介

        Ice版本:Ice-3.1.1

        操作系统:Windows XP SP2

        JDK版本:JDK 1.6

        安全性对于许多分布式应用程序来说是一个重要的考虑因素,无论是在企业内部网还是在不可信的网络,如Internet。保护敏感的信息,确保其完整性,并验证通信双方的身份的能力,这些能力对于开发安全的应用程序来说是必不可少的。考虑到这些目标,Ice提供了这些功能的IceSSL插件,IceSSL插件使用SSL协议。

2. 配置IceSSL

        将IceSSL合并到你的应用程序中,需要安装IceSSL插件,根据你的安全需求进行配置,并创建SSL端点。

        安装IceSSL插件通过在配置文件中添加Ice.Plugin属性,不需要修改应用程序源代码。

2.1. C++应用程序

        C++ IceSSL插件的可执行代码驻留在Unix的共享库上和Windows上的一个动态链接库(DLL)中。如下所示属性Ice.Plugin

        Ice.Plugin.IceSSL=IceSSL:createIceSSL 

        该属性值IceSSLcreateIceSSL允许UnixWindowsIce运行时寻找到IceSSL库(在Unix 和Windows上),并且初始化插件。该库必须出现在共享库路径(大多数Unix 平台的LD_LIBRARY_PATH,在Windows平台上的path环境变量)指定的目录中。

2.2. Java应用程序

        Ice.Plugin属性配置如下:

        Ice.Plugin.IceSSL=IceSSL.PluginFactory 

        IceSSL.PluginFactory 是一个class类名,允许ice运行时初始化IceSSL插件,这些类包含在Ice.jar 包中。

2.3. 创建SSL端点

        安装了IceSSL 插件之后,就可以在端点中使用一种新协议ssl了。例如,下面的端点列表创建了一个TCP 端点、一个SSL 端点,以及一个UDP 端点:

        MyAdapter.Endpoints=tcp -p 8000:ssl -p 8001:udp -p 8000

        如这个例子所演示的,UDP端点可以使用和TCPSSL端点相同的端口号,因为UDP是一种不同的协议,有自己的端口集。但TCP端点和SSL端点不能使用同一个端口号,因为SSL 在本质上是位于TCP 之上的一个层面。在串化代理中使用SSL 同样直截了当:

        MyProxy=MyObject:tcp -p 8000:ssl -p 8001:udp -p 8000

2.4. 安全考虑事项

        像上面的例子那样,对象适配器的端点使用多种协议,对安全有一些明显的影响。如果意图是用SSL来保护会话通信,或者是限制对服务器的访问,那么应该只定义SSL端点。

        但在有些情况下,使用不安全的端点协议也有好处。下图阐释了一种环境,在防火墙以内可以使用TCP,但外部客户必须使用SSL

 IceSSL插件配置

         图中的防火墙被配置成阻塞外部对TCP端口8000的访问,并把与端口8001 的连接转到服务器的机器。

        在防火墙以内使用TCP的一个原因是,它比SSL效率更高,使用时所需的管理工作更少。当然,这里的例子假定内部客户是可信的,在许多环境中事情未必如此。

2.5. 配置IceSSL

         配置环境

IceGrid节点

IP地址

注册器(registry

192.168.1.10

节点1Node1

192.168.1.20

节点2Node2

192.168.1.30

客户端(client

192.168.1.40

         注册器配置:

[plain] view plain copy
  1. # IceSSL properties  
  2. Ice.Plugin.IceSSL=IceSSL:createIceSSL  
  3. IceSSL.DefaultDir=C:\IceGrid  
  4. IceSSL.CertFile=registry_cert.pem  
  5. IceSSL.KeyFile=registry_key.pem  
  6. IceSSL.CertAuthFile=ca_cert.pem  
  7. IceSSL.Password=123456  
  8. # Registry properties  
  9. IceGrid.Registry.Client.Endpoints=ssl -p 4065:tcp -p 4066  
  10. IceGrid.Registry.Server.Endpoints=ssl  
  11. IceGrid.Registry.Internal.Endpoints=ssl  
  12. IceGrid.Registry.AdminPermissionsVerifier=IceGrid/NullPermissionsVerifier  
  13. IceGrid.Registry.PermissionsVerifier=IceGrid/NullPermissionsVerifier  
  14. IceGrid.Registry.Data=C:\IceGrid\registry  
  15. IceGrid.Registry.Admin.Endpoints=default  
  16. #Log properties  
  17. IceGrid.Registry.Trace.Adapter=1  
  18. IceGrid.Registry.Trace.Node=2  

        启动注册器我们使用的是icegridregistry.exe可执行程序,所以配置IceSSL插件使用C++配置IceSSL:createIceSSLIceSSL.Password属性配置了明文密码,这不是一个安全的做法。更好的设置密码的方式,参考官方文档。        

        配置说明:       

属性

说明

Ice.Plugin.IceSSL

开启IceSSL插件服务的主类

IceSSL.DefaultDir

数字证书存放的目录

IceSSL.CertFile

注册器的数字证书文件,pem格式

IceSSL.KeyFile

注册器的数字证书对应的私钥文件,pem格式

IceSSL.CertAuthFile

给注册器的数字证书签名的根证书,pem格式

IceSSL.Password

读取私钥时使用的密码

        其他的属性不属于IceSSL插件特有的配置,在此不再次说明。

         IceGrid.Registry.Client.Endpoints属性提供了两种协议,添加了ssl协议,保留了tcp协议,保留的tcp协议提供给客户端连接注册器使用,客户端连接注册器只是为了获取一个可用的代理,不需要使用加密通信,这样也可以降低对性能的影响。

        管理客户端配置:

[plain] view plain copy
  1. Ice.Plugin.IceSSL=IceSSL:createIceSSL  
  2. IceSSL.DefaultDir=C:\IceGrid  
  3. IceSSL.CertFile=admin_cert.pem  
  4. IceSSL.KeyFile=admin_key.pem  
  5. IceSSL.CertAuthFile=ca_cert.pem  
  6. IceSSL.Password=123456  
  7. Ice.Default.Locator=IceGrid/Locator:ssl -h 192.168.1.10 -p 4065  

        管理客户端发布我们的应用程序,启动管理客户端我们使用的是icegridadmin.exe可执行程序,所以配置IceSSL插件使用C++配置IceSSL:createIceSSL      

        部署文件:        

[html] view plain copy
  1. <icegrid>  
  2.     <application name="PrinterApplication">  
  3.         <replica-group id="PrinterAdapters">  
  4.             <load-balancing type="round-robin" />  
  5.             <object identity="SimplePrinter" type="iceGrid.sampleAdapterLocator.servant.PrinterI"/>  
  6.         </replica-group>  
  7.         <server-template id="PrinterServerTemplate">  
  8.             <parameter name="index" />  
  9.             <server id="PrinterServer${index}" exe="java" activation="on-demand">  
  10.                 <option>-jar</option>  
  11.                 <option>C:\PrinterApp.jar</option>  
  12.                 <adapter name="PrinterAdapter" replica-group="PrinterAdapters"  
  13.                     endpoints="ssl" />  
  14.                 <property name="Identity" value="SimplePrinter"/>  
  15.             </server>  
  16.         </server-template>  
  17.         <node name="Node1">  
  18.             <server-instance template="PrinterServerTemplate"  
  19.                 index="1" />  
  20.         </node>  
  21.         <node name="Node2">  
  22.             <server-instance template="PrinterServerTemplate"  
  23.                 index="2" />  
  24.         </node>  
  25.     </application>  
  26. </icegrid>  

        和普通的发布文件相比,只需要将适配器adapter 的端点修改为ssl即可。

        节点1配置:

[plain] view plain copy
  1. Ice.Plugin.IceSSL=IceSSL:createIceSSL  
  2. IceSSL.DefaultDir=C:\IceGrid  
  3. IceSSL.CertFile=node_cert.pem  
  4. IceSSL.KeyFile=node_key.pem  
  5. IceSSL.CertAuthFile=ca_cert.pem  
  6. IceSSL.Password=123456  
  7. # Node properties  
  8. IceGrid.Node.Endpoints=ssl  
  9. IceGrid.Node.Name=Node1  
  10. IceGrid.Node.Data=C:\IceGrid\node  
  11.    
  12. Ice.Default.Locator=IceGrid/Locator:ssl -h 192.168.1.10 -p 4065  
  13. #log properties  
  14. IceGrid.Node.Trace.Activator=3  
  15. IceGrid.Node.Trace.Adapter=3  
  16. IceGrid.Node.Trace.Server=3  
        启动节点1我们使用的是icegridnode.exe可执行程序,所以配置IceSSL插件使用C++配置IceSSL:createIceSSL节点2使用相同的配置,修改IceGrid.Node.Name=Node2

         java应用服务程序:

[plain] view plain copy
  1. Ice.Plugin.IceSSL=IceSSL.PluginFactory  
  2. IceSSL.DefaultDir=C:\IceGrid  
  3. IceSSL.Keystore=cert.jks  
  4. IceSSL.Truststore=ca.jks  
  5. IceSSL.Password=123456  
  6. IceSSL.Alias=printservercert  
  7. Ice.ThreadPerConnection=1  
  8.    
  9. #IceSSL.Ciphers=NONE (RSA.*AES) !(EXPORT)  
  10. #Log   
  11. IceSSL.Trace.Security=3  
  12. Ice.Trace.Protocol=1  
  13. Ice.Trace.Network=3  

        应用服务是我们自己使用java开发的服务器程序,使用该配置文件初始化通信器Ice.Communicator,java开发的应用和C++开发的应用程序使用IceSSl插件,在配置上有一些区别,插件类为IceSSL.PluginFactory,此类在Ice.jar包中,

        IceSSL使用Java的原始格式存储**和证书:**库(keystore)。**库作为一个文件包含**对及相关证书,通常使用keytool工具管理**库文件。

        密码被分配到每个keystore中的**对,以及**库本身,即程序在读取**库和**库中的**等信息时,都需要提供密码,该密码由IceSSL.Password提供。IceSSL要求**库中的**存取必须要使用密码,但**库的密码是可选的。如果一个**库的密码是指定的,是只用于验证**库的完整性。IceSSL要求**库中所有的**对使用相同的密码。

         配置说明:

属性

说明

Ice.Plugin.IceSSL

开启IceSSL插件服务的主类

IceSSL.DefaultDi

**库文件存放的目录

IceSSL.Keystore

服务器**库,存放根证书签发的服务器证书

IceSSL.Truststore

受信任的根证书存放在此**库中

IceSSL.Password

读取**时使用的密码

IceSSL.Alias

如果服务器**库中有多个证书条目,此属性指定服务器使用哪个证书与客户端建立安全通信。

Ice.ThreadPerConnection

如果属性值被设置为大于零,Ice运行时对于每一个连接都会创建一个线程。

        服务器示例代码:

[java] view plain copy
  1. public class Server extends Ice.Application {  
  2.     public int run(String[] args) {  
  3.         //创建名为SimplePrinterAdapter的适配器,         
  4.         Ice.ObjectAdapter adapter = communicator().createObjectAdapter("PrinterAdapter");  
  5.         //实例化一个PrinterI对象,为Printer接口创建一个服务对象  
  6.         Ice.Object object = new PrinterI();  
  7.         //将服务单元增加到适配器中,并给服务对象指定名称为SimplePrinter,该名称用于唯一确定一个服务单元  
  8.         adapter.add(object, Ice.Util.stringToIdentity("SimplePrinter"));  
  9.         //**适配器,这样做的好处是可以等到所有资源就位后再触发  
  10.         adapter.activate();  
  11.         //让服务在退出之前,一直持续对请求的监听  
  12.         communicator().waitForShutdown();  
  13.         return 0;  
  14.     }  
  15.     public static void main(String[] args) {  
  16.         Server app = new Server();  
  17.         System.out.println("服务器已经启动!");  
  18.         String conf = “c:\\conf\\server.cnf”  
  19.         System.exit(app.main("Server", args,conf ));  
  20.     }  
  21. }  
        服务器使用java语言实现了一个简单的打印功能,将客户端发送到服务器端的信息打印到终端。服务端在调用app.main("Server", args,conf )的时候,会使用conf 变量指定的配置文件初始化通信器,同时会开启IceSSL插件。

        客户端配置:

[plain] view plain copy
  1. Ice.Plugin.IceSSL=IceSSL.PluginFactory  
  2. IceSSL.DefaultDir=C:\IceGrid  
  3. IceSSL.Keystore=cert.jks  
  4. IceSSL.Truststore=ca.jks  
  5. IceSSL.Password=123456  
  6. IceSSL.Alias=usercert  
  7. Ice.ThreadPerConnection=1  
  8. Ice.Default.Locator=IceGrid/Locator:tcp -h 192.168.1.10 -p 4066  
  9. #Ice.Trace.Network=3  
        客户端在建立Ice.Communicator通信器时,使用此属性集初始化通信器。在本文的例子中,客户端同样是使用java语言开发。Ice.Default.Locator属性指定注册器所在的服务器,使用的是tcp协议,客户端与注册器通信内容,不会包含太过重要的信息,因此没有必要使用ssl协议建立通信。

        客户端示例代码:

[java] view plain copy
  1. public class Client extends Ice.Application {  
  2.     public int run(String[] args) {  
  3.         //获取Printer的远程代理,这里使用的stringToProxy方式  
  4.         Ice.ObjectPrx base = communicator().stringToProxy("SimplePrinter");  
  5.         //通过checkedCast向下转换,获取Printer接口的远程,并同时检测根据传入的名称获取的服务单元是否Printer的代理接口,如果不是则返回null对象  
  6.         Demo.PrinterPrx printer = Demo.PrinterPrxHelper.checkedCast(base);  
  7.         if (printer == nullthrow new Error("Invalid proxy");  
  8.         //把Hello World传给服务端,让服务端打印出来,因为这个方法最终会在服务端上执行  
  9.         for(int i = 0;i<10;i++){  
  10.             String ret = printer.printString("Hello World!哈哈");  
  11.             System.out.println(ret);  
  12.         }  
  13.         return 0;  
  14.     }  
  15.     public static void main(String[] args) {  
  16.         Client app = new Client();  
  17.         System.exit(app.main("Client", args,"C:\\client.conf"));  
  18.     }  
  19. }  
        服务端在调用app.main("Client", args,"C:\\client.conf")的时候,会使用client.conf配置文件初始化通信器,同时会开启IceSSL插件。

3. 安装证书

        在开发过程中,有一个简单的方法创建新的证书(也可以使用其他方式制作证书,只要符合Ice要求的证书格式都可以)。OpenSSL包括所有必要的基础设施来设立自己的证书颁发机构(CA),但是我们必须对OpenSSL非常的熟悉。为了简化这个过程,Ice提供了一系列Python脚本(对应Ice-3.1.1版本的Python版本为2.7.5),位于Ice安装目录下的config/ca子目录,这些Python脚本隐藏了复杂的OpenSSL操作过程,并允许我们快速执行必要的任务:

        l 初始化一张新的根证书

        l 生成新的证书请求

        l 给证书请求签名,创建一个有效的证书链

        l 转换证书,以匹配特定的平台需求

        首先需要在系统中安装Python-2.7.5版本,才能够顺利执行Python脚本。

        设置环境变量ICE_CA_HOME,指定一个目录,制作证书的过程中,运行Python脚本生成的文件,将存放在该目录中。

3.1. 初始化root CA

        通过以下的命令初始化一个根证书

        python initca.py [--no-password] [--overwrite] 

        --overwrite操作会覆盖一个已经存在的根证书,如果对CA的私钥不做加密处理可以使用--no-password操作。

         假设ICE_CA_HOME环境变量设置为c:\iceca,则会在该目录下生产两个文件,req.cnf和ca_cert.pem。ca_cert.pem文件包含根证书,我们的IceSSL配置文件必须指定该根证书作为我们的信任证书,C++程序通过IceSSL.CertAuthFile=C:\iceca\ca_cert.pem 指定,在java中,我们需要添加该证书到信任域中,使用如下的命令:

        keytool -import -trustcacerts -file ca_cert.pem -keystore ca.jks 

         ca.jks是java支持的**库文件格式,Java通过IceSSL.Truststore属性指定该根证书。

3.2. 生成证书请求

        生成证书请求使用如下命令:

        python req.py [--overwrite] [--no-password] [--node|--registry|--server|--user] 

        此脚本会查找req.cnfca_cert.pem文件,在ICE_CA_HOME 环境变量指定的目录下,然后生成两个文件:一个私钥和一个文件包含证书请求。请求文件必须被传送到证书颁发机构签名,产生一个有效的证书链。

         --node--registry代表IceGrid 节点和注册器,--server表示Ice 的服务器,--user表示一个人或者一个客户端,这些操作只是影响着生成文件的名称,如服务器需要一个证书,可以使用命令python req.py --server,执行完脚本之后生成的文件名字为server_key.pemserver_req.pem。节点证书请求、应用程序证书请求、注册器证书请求、客户端证书请求,都需要分别执行这一条命令。server_key.pem文件为服务器生成的新的私钥,这个文件必须被安全保存,server_req.pem为服务器证书请求文件。

3.3. 签名证书请求

        使用如下命令:

        sign.py --in <req> --out <cert> 

        输入文件req为证书请求文件,输出文件cert是证书链,如给节点证书请求签名,使用如下命令:

        python sign.py --in node_req.pem --out node_cert.pem 

3.4. 转换证书格式

        对于java用户来说,私钥和证书链必须被转换成合适的格式,使用如下命令:

        python import.py [--overwrite] [--java alias cert key keystore] 

        如从节点的证书链文件中导出节点的私钥和节点证书到一个java**库中,使用如下命令:

        python import.py --java mycert node_cert.pem node_key.pem cert.jks 

        在**库cert.jks文件中,Mycert为一个节点证书条目的别名,IceSSL配置文件通过属性IceSSL.Keystore来指定这个**库。