SecretFlow is designed for fast simulation on a single host or on multiple nodes with single ray cluster.
Note
SecretFlow with single ray cluster is for simulation only. Please refer to production
section below for production.
Use secretflow.init
directly to run secretflow in standalone mode.
>>> import secretflow as sf
>>> sf.init(['alice', 'bob', 'carol'], address='local')
The following is an example showing how to build a cluster consisting of alice and bob on multiple nodes.
Start a head node on your first machine with the tag "alice".
NOTE
-
Remember to use the real ip and port instead.
-
{"alice": 16}
means that alice can run up to 16 workers at the same time. Just feel free to change it if you like.
ray start --head --node-ip-address="ip" --port="port" --resources='{"alice": 16}' --include-dashboard=False --disable-usage-stats
Head node starts successfully if you see "Ray runtime started." in the screen output.
Now we have a cluster with a head node only, let us start more nodes.
Start a node with the tag "bob" on another machine. The node will connect to the head node and join the cluster.
Note
Replace ip:port
with the node-ip-address
and port
of head node please.
ray start --address="ip:port" --resources='{"bob": 16}' --include-dashboard=False --disable-usage-stats
The node starts successfully if you see "Ray runtime started." in the screen output.
You can repeat the step above to start more nodes with using other parties as resources tag as you like.
Now you can start SecretFlow and run your code.
Fill address
of sf.init
with the node-ip-address
and port
of head node please.
>>> import secretflow as sf
# Replace with the `node-ip-address` and `port` of head node.
>>> sf.init(address='ip:port')
>>> alice = sf.PYU('alice')
>>> bob = sf.PYU('bob')
>>> alice(lambda x : x)(2)
<secretflow.device.device.pyu.PYUObject object at 0x7fe932a1a640>
>>> bob(lambda x : x)(2)
<secretflow.device.device.pyu.PYUObject object at 0x7fe6fef03250>
In some cases you would like to shut down the cluster, the following command will help you. Remember to run the command on all machines.
Note that all ray processors on the machine will be stopped, which means all ray clusters will be stopped.
ray stop
SPU
consists of multi workers on different nodes.
For performance reasons, the major part of SPU is written in C++.
SPU is based on Brpc, which indicates it has a separated service mesh independent of Ray's networking.
In a word, you need to assign different ports for the SPU for now.
We are working on merging them.
A typical SPU config is as follows.
Tips
- Replace
ip:port
insf.init
with thenode-ip-address
andport
of head node please. - Fill
address
ofalice
with the ip which can be accessed bybob
and choose an unused port. - Fill
address
ofbob
with the ip which can be accessed byalice
and choose an unused port.
import spu
import secretflow as sf
# Use ray head adress please.
sf.init(parties=['alice', 'bob'], address='ip:port')
cluster_def={
'nodes': [
{
'party': 'alice',
'id': '0',
# Use the ip and port of alice instead.
# Please choose an unused port.
'address': 'address:port',
'listen_addr': '0.0.0.0:port'
},
{
'party': 'bob',
'id': '1',
# Use the ip and port of bob instead.
# Please choose an unused port.
'address': 'address:port',
'listen_addr': '0.0.0.0:port'
},
],
'runtime_config': {
'protocol': spu.spu_pb2.SEMI2K,
'field': spu.spu_pb2.FM128,
'sigmoid_mode': spu.spu_pb2.RuntimeConfig.SIGMOID_REAL,
}
}
spu = sf.SPU(cluster_def=cluster_def)
For more configurations of SPU, please refer to SPU config
Note
You will see the usage of setup a spu in many toturials. But
be careful that it works only in standalone mode because sf.utils.testing.cluster_def
use 127.0.0.1
as the default ip.
>>> spu = sf.SPU(sf.utils.testing.cluster_def(['alice', 'bob', 'carol']))
SecretFlow provides multi controller mode for production with enhanced security. The following will guide you to deploy SecretFlow for production.
A SecretFlow cluster for production consists of serveral ray clusters, and every party has its own ray cluster.
The following is an example showing how to build a cluster consisting of alice and bob for production.
alice
starts its ray cluster firstly.
ray start --head --node-ip-address="ip" --port="port" --include-dashboard=False --disable-usage-stats
Head node starts successfully if you see "Ray runtime started." in the screen output.
Then alice
initializes SecretFlow with a cluster config.
Tips
- Replace
ip:port
insf.init
with thenode-ip-address
andport
of head node please. - Fill
address
ofalice
with the address which can be accessed bybob
. Remember to choose an unused port. - Fill
address
ofbob
with the address which can be accessed byalice
. Remember to choose an unused port. - Note that
self_party
is alice.
cluster_config ={
'parties': {
'alice': {
# replace with alice's real address.
'address': 'ip:port',
'listen_addr': '0.0.0.0:port'
},
'bob': {
# replace with bob's real address.
'address': 'ip:port',
'listen_addr': '0.0.0.0:port'
},
},
'self_party': 'alice'
}
sf.init(address='ip:port', cluster_config=cluster_config)
# your code to run.
bob
starts its ray cluster firstly.
ray start --head --node-ip-address="ip" --port="port" --include-dashboard=False --disable-usage-stats
Head node starts successfully if you see "Ray runtime started." in the screen output.
Then bob
initializes SecretFlow with a cluster config almost same as alice
except for self_party
.
Tips
- Replace
ip:port
insf.init
with thenode-ip-address
andport
of head node please. - Fill
address
ofalice
with the address which can be accessed bybob
. Remember to choose an unused port. - Fill
address
ofbob
with the address which can be accessed byalice
. Remember to choose an unused port. - Note that
self_party
isbob
.
cluster_config ={
'parties': {
'alice': {
# replace with alice's real address.
'address': 'ip:port',
'listen_addr': '0.0.0.0:port'
},
'bob': {
# replace with bob's real address.
'address': 'ip:port',
'listen_addr': '0.0.0.0:port'
},
},
'self_party': 'bob'
}
sf.init(address='ip:port', cluster_config=cluster_config)
# your code to run.
Just same as simulation, please refer to the previous for details.
-
Enable tls Authentication.
SecretFlow can be configured to use TLS on cross-silo gRPC channels.
An example for alice.
tls_config = { "cert": { # Alice's cert and key. "ca_cert": "cacert.pem", "cert": "servercert.pem", "key": "serverkey.pem", }, "client_certs": { # peer's cert. "bob": { "ca_cert": "bob's cacert.pem", "cert": "bob's servercert.pem", } } } sf.init(address='ip:port', cluster_config=cluster_config, tls_config=tls_config )
An example for bob.
tls_config = { "cert": { # Bob's cert and key. "ca_cert": "cacert.pem", "cert": "servercert.pem", "key": "serverkey.pem", }, "client_certs": { # peer's cert. "alice": { "ca_cert": "alice's cacert.pem", "cert": "alice's servercert.pem", } } } sf.init(address='ip:port', cluster_config=cluster_config, tls_config=tls_config )
-
Enhanced serialization/deserialization.
SecretFlow uses
pickle
in serialization/deserialization which is vulnerable. You can setcross_silo_serializing_allowed_list
when init SecretFlow to specify an allowlist to restrict serializable objects. An example could be (You should not use this demo directly. Configure it to your actual needs.)allowed_list = { "numpy.core.numeric": ["*"], "numpy": ["dtype"], } sf.init(address='ip:port', cluster_config=cluster_config, cross_silo_serializing_allowed_list=allowed_list )