-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kmesh enable ipsec #1030
Kmesh enable ipsec #1030
Conversation
bpf/kmesh/bpf2go/bpf2go.go
Outdated
@@ -20,16 +20,20 @@ package bpf2go | |||
// go run github.com/cilium/ebpf/cmd/bpf2go --help | |||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshCgroupSock ../ads/cgroup_sock.c -- -I../ads/include -I../../include -I../../../api/v2-c -DCGROUP_SOCK_MANAGE -DKERNEL_VERSION_HIGHER_5_13_0=1 | |||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshCgroupSockWorkload ../workload/cgroup_sock.c -- -I../workload/include -I../../include -I../probes -DKERNEL_VERSION_HIGHER_5_13_0=1 | |||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshSockops ../ads/sockops.c -- -I../ads/include -I../../include -I../../../api/v2-c -DKERNEL_VERSION_HIGHER_5_13_0=1 | |||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshTracePoint ../ads/tracepoint.c -- -I../ads/include -I../../include -DKERNEL_VERSION_HIGHER_5_13_0=1 | |||
//not go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang --cflags $EXTRA_CFLAGS --cflags $EXTRA_CDEFINE KmeshSockops ../ads/sockops.c -- -I../ads/include -I../../include -I../../../api/v2-c -DKERNEL_VERSION_HIGHER_5_13_0=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is no modification, it will be cleaned up later
__type(value, struct nodeinfo); | ||
__uint(map_flags, BPF_F_NO_PREALLOC); | ||
__uint(max_entries, MAP_SIZE_OF_NODEINFO); | ||
} map_of_nodeinfo SEC(".maps"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
map name need a prefix: km_
defer file.Close() | ||
|
||
is.ipSecLoadLock.Lock() | ||
defer is.ipSecLoadLock.Unlock() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to unlock after line 108 is executed.
No need to defer
log.Infof("start watching file %s", IpSecKeyFile) | ||
|
||
var timerC <-chan time.Time | ||
for { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I end the loop?
ipsecKeyBase := ipsecController.ipsecKey.GetIPSecKey() | ||
ipsecController.kmeshNodeInfo.Spec.Spi = ipsecKeyBase.Spi | ||
|
||
myNodeName := os.Getenv("NODE_NAME") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: localNodeName? or onle nodeName
kniKey := lpm_key{ | ||
trie_key: uint32(prefix), | ||
} | ||
ip, _ := netip.ParseAddr(cidr[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this here to parse the cidr to get the IP? If so, see net.ParseCIDR
} | ||
|
||
func (ic *ipsecController) isMine(name string) bool { | ||
myNodeName := os.Getenv("NODE_NAME") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe can use a global variable to store nodeName
log.Errorf("failed to create kmesh node info to k8s: %v", err) | ||
return | ||
} | ||
tmpUpdate, err := ic.kniClient.Get(context.TODO(), ic.kmeshNodeInfo.Name, metav1.GetOptions{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it take a while to wait for the kmeshNode to be created?
ic.ipsecKey.StartWatch(ipsecUpdateChan) | ||
|
||
go func() { | ||
for { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How to end this loop?
pkg/utils/kubeclient.go
Outdated
@@ -39,6 +41,21 @@ func GetK8sclient() (kubernetes.Interface, error) { | |||
return clientset, nil | |||
} | |||
|
|||
func GetKmeshNodeInfoClient() (kni_versioned.Interface, error) { | |||
var clientset kni_versioned.Interface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary?
a4f8f46
to
f35b8d7
Compare
bpf/kmesh/workload/include/tc.h
Outdated
void *begin = (void *)(long)(ctx->data); | ||
void *end = (void *)(long)(ctx->data_end); | ||
|
||
// eth header |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is already a similar parse function (https://github.com/kmesh-net/kmesh/blob/main/bpf/kmesh/workload/xdp.c#L71), can it be reused or abstracted into a tool function.
pkg/cni/plugin/plugin.go
Outdated
} | ||
|
||
if link, err = netlink.LinkByIndex(ifIndex); err != nil { | ||
return fmt.Errorf("failed ot link valid interface, %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return fmt.Errorf("failed ot link valid interface, %v", err) | |
return fmt.Errorf("failed to link valid interface, %v", err) |
pkg/cni/plugin/plugin.go
Outdated
} | ||
|
||
if err = utils.AttchTCProgram(link, tc, utils.TC_DIR_INGRESS); err != nil { | ||
return fmt.Errorf("failed ot attach tc program, %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return fmt.Errorf("failed ot attach tc program, %v", err) | |
return fmt.Errorf("failed to attach tc program, %v", err) |
@bitcoffeeiux it would be better to upload the design doc together for easier review :) |
@bitcoffeeiux Any update on this PR? |
aaaeb32
to
010c40b
Compare
010c40b
to
3e7fc5c
Compare
3e7fc5c
to
85e14a6
Compare
__type(value, struct nodeinfo); | ||
__uint(map_flags, BPF_F_NO_PREALLOC); | ||
__uint(max_entries, MAP_SIZE_OF_NODEINFO); | ||
} map_of_nodeinfo SEC(".maps"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} map_of_nodeinfo SEC(".maps"); | |
} km_nodeinfo SEC(".maps"); |
Or rename the map in config.h.
bpf/kmesh/general/tc_mark_decrypt.c
Outdated
return TC_ACT_OK; | ||
} | ||
nodeid = nodeinfo->nodeid; | ||
ctx->mark = (nodeid << 16) + 0x00d0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this 0x00d0 and is it possible to add a comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means that the packet needs to be decrypted by xfrm.
bpf/kmesh/general/tc_mark_encrypt.c
Outdated
if (!nodeinfo) { | ||
return TC_ACT_OK; | ||
} | ||
ctx->mark = ((nodeinfo->nodeid) << 16) + ((nodeinfo->spi) << 8) + 0x00e0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which one?
|
||
Kmesh使能ipsec时,需要精细化控制ipsec数据加密行为,这其中要求Kmesh具有节点之间的信息同步机制。当前主要场景基于云原生业务场景,信息同步机制基于K8s集群api-server构建,依赖Kmesh自定义结构体来完成数据存储。 | ||
|
||
CRD数据结构定义如下: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The meaning of each field in crd can be illustrated from the contents of type.go
|
||
### 4.3 Kmesh IPsec通信路径 | ||
|
||
 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The image can be centred
"reflect" | ||
"syscall" | ||
|
||
"github.com/cilium/ebpf" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
golint error
pkg/cni/plugin/plugin.go
Outdated
@@ -194,6 +255,11 @@ func CmdAdd(args *skel.CmdArgs) error { | |||
log.Error(err) | |||
return err | |||
} | |||
|
|||
if err := enableTcEgress(args); err != nil { | |||
err = fmt.Errorf("failed to set tc to dev %v, err is %v", args.IfName, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what tc means. can be stated in error info
return NULL; | ||
} | ||
key.trie_key.prefixlen = 128; | ||
IP6_COPY(key.ip.ip6, ip6); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At some place, we use bpf_memcpy
daemon/options/encryption.go
Outdated
} | ||
|
||
func (c *encryptionConfig) AttachFlags(cmd *cobra.Command) { | ||
cmd.PersistentFlags().BoolVar(&c.EnableIPsec, "enable-ipsec", false, "enable ipsec in daemon process") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: enable ipsec in service to service communication
deploy/yaml/clusterrole.yaml
Outdated
@@ -11,3 +11,6 @@ rules: | |||
- apiGroups: ["apps"] | |||
resources: ["daemonsets"] | |||
verbs: ["get"] | |||
- apiGroups: ["kmesh.net"] | |||
resources: ["kmeshnodeinfos"] | |||
verbs: ["get", "create", "update", "patch", "list", "watch"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
patch, update, which one do you use?
pkg/cni/plugin/plugin.go
Outdated
} | ||
|
||
getVethPeerLinkNum := func(netns.NetNS) error { | ||
if err = utils.ExecuteWithRedirect("ethtool", ethtoolArgs, &output); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should use go code
Spi int8 `json:"spi"` | ||
NicIPs []string `json:"nicIP"` | ||
BootID string `json:"bootid"` | ||
Cirds []string `json:"cirds"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add some comments for the above fields
myNode *v1.Node | ||
} | ||
|
||
func NewIPsecController(k8sClientSet kubernetes.Interface) (*IpsecController, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
func NewIPsecController(k8sClientSet kubernetes.Interface) (*IpsecController, error) { | |
func NewIPSecController(k8sClientSet kubernetes.Interface) (*IpsecController, error) { |
pkg/utils/hash16.go
Outdated
func (s *Sum) Write(input []byte) (n int, err error) { | ||
var sum uint64 = 0 | ||
for pos, i := range input { | ||
si := uint32(i) | ||
switch pos % 4 { | ||
case 0: | ||
case 1: | ||
si = si << 8 | ||
case 2: | ||
si = si << 16 | ||
case 3: | ||
si = si << 24 | ||
} | ||
sum += uint64(si) | ||
} | ||
for sum&0xffffffffffff0000 != 0 { | ||
sum = sum&0xffff + sum>>16 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you want to do, just remind that golang lib has hash function
pkg/utils/tc.go
Outdated
return nil | ||
} | ||
|
||
func DetchTCProgram(link netlink.Link, tc *ebpf.Program) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not called anywhere
pkg/kube/generate.sh
Outdated
|
||
kube::codegen::gen_client \ | ||
--with-watch \ | ||
--output-dir "${SCRIPT_ROOT}/pkg/kube/exnodeinfo" \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you use exnodeinfo
} | ||
|
||
func (ic *IpsecController) handleAllKmeshNodeInfo() bool { | ||
kmeshNodeInfoList, err := ic.kniClient.List(context.TODO(), metav1.ListOptions{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Donot use this list, since you have created a informer, use its List()
if ic.isMine(node.Name) { | ||
continue | ||
} | ||
if err = ic.handleOtherNodeInfo(&node); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if err = ic.handleOtherNodeInfo(&node); err != nil { | |
if err = ic.handleNodeInfo(&node); err != nil { |
} | ||
|
||
if item.action == ActionAdd || item.action == ActionUpdate { | ||
kniNodeInfo, err := ic.kniClient.Get(context.TODO(), item.name, metav1.GetOptions{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
donot use this one, use thae Get method from informer
} | ||
} | ||
|
||
func (ic *IpsecController) processNextItem() bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function cannot return false, otherwise the Run( will exit)
|
||
其他节点: | ||
|
||
- node节点新增以后并将自己的kmeshnodeinfo上传api-server后,说明当前node节点上ipsec规则已准备好,当前kmesh-daemon仅需将对应node的state、policy、map更新即可 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What will happen when a new node has already send traffic to the dst node, before the dst node setup the following policy ready
pkg/cni/plugin/plugin.go
Outdated
if strings.Compare(line[0], "peer_ifindex") != 0 { | ||
continue | ||
} | ||
if ifIndex, err = strconv.Atoi(strings.Trim(line[1], " ")); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of trim, you can split ": " or just " "
pkg/cni/plugin/plugin.go
Outdated
} | ||
|
||
if ifIndex == 0 { | ||
return fmt.Errorf("can not found valid if index") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return fmt.Errorf("can not found valid if index") | |
return fmt.Errorf("can not find valid peer interface index") |
pkg/cni/plugin/plugin.go
Outdated
@@ -194,6 +255,11 @@ func CmdAdd(args *skel.CmdArgs) error { | |||
log.Error(err) | |||
return err | |||
} | |||
|
|||
if err := enableTcEgress(args); err != nil { | |||
err = fmt.Errorf("failed to set tc to dev %v, err is %v", args.IfName, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
err = fmt.Errorf("failed to set tc to dev %v, err is %v", args.IfName, err) | |
err = fmt.Errorf("failed to link tc to dev %v, err is %v", args.IfName, err) |
81dccb7
to
8d7d668
Compare
bpf/kmesh/general/tc_mark_encrypt.c
Outdated
if (!nodeinfo) { | ||
return TC_ACT_OK; | ||
} | ||
ctx->mark = ((nodeinfo->nodeid) << 16) + 0x00e0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: ((nodeinfo->nodeid) << 16) | 0x00e0;
ctl/secret/secret.go
Outdated
Use: "secret", | ||
Short: "Use secrets to generate secret configuration data for IPsec", | ||
Example: `# Use secrets to generate secret configuration data for IPsec: | ||
kmeshctl secret aeadKey aeadLength, only support rfc4106(gcm(aes))`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please provide complete usage guide
ctl/secret/secret.go
Outdated
if err == nil { | ||
return | ||
} | ||
_, err = clientset.Kube().CoreV1().Secrets(utils.KmeshNamespace).Update(context.TODO(), secret, metav1.UpdateOptions{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm. can you only call this when .Get return non err
deploy/yaml/clusterrole.yaml
Outdated
@@ -9,5 +9,8 @@ rules: | |||
resources: ["pods","services","namespaces","nodes"] | |||
verbs: ["get", "update", "patch", "list", "watch"] | |||
- apiGroups: ["apps"] | |||
resources: ["daemonsets"] | |||
resources: ["daemonsets", "secret"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you donot reply on secret get, but use filewatch
} | ||
for _, rawLocalAddr := range c.kmeshNodeInfo.Spec.Addresses { | ||
localAddr := net.ParseIP(rawLocalAddr) | ||
if addr.IP.Equal(localAddr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does this check mean
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mount the tc program only when NodeInternalIP exists on the NIC.
} | ||
|
||
for _, addr := range node.Spec.Addresses { | ||
for _, cidr := range c.ipsecHandler.nodeInfos[addr].cidrs { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do not make node name as the key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also use the name of the node as the key. In the current processing process, such as creating state rules, the iphandler processes information based on IP addresses and uses IP addresses to classify information.
return err | ||
} | ||
|
||
_, remoteCIDR, err := net.ParseCIDR("0.0.0.0/0") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is a const, we can define one
IpSecKeyFile = "./kmesh-ipsec/ipSec" | ||
) | ||
|
||
type ipSecInfo struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is quite similar as KmeshNodeInfo, can you use it
d32dd79
to
93a5a6a
Compare
Kmesh introduce IPsec encryption to encrypt communicatioon between nodes, which is critical to maintaining communication security. This submission includes come preliminary design of ipsec and outlines the basic data path for Kmesh using IPsec. Signed-off-by: bitcoffee <liuxin350@huawei.com>
We have added two new eBPF tc programs to mark traffic data. `tc_mark_encrypt` runs on the NIC of the pod. Currently, the veth NIC is supported. When the veth node receives a data packet, tc programs determines whether the traffic needs to be encrypted based oon the target information. If the traffic needs to be encrypted, tc add l marker to the packet and sends it to the IPsec of the host for processing. `tc_mark_decrypt` runs on the NIC of a node. After receiving an IPsec packet, mark the decrypted IPsec packet and determine whether to send the packet to the backend for processing or directly discarded by IPsec. Signed-off-by: bitcoffee <liuxin350@huawei.com>
kmesh node info is an CRD. This resource is used to transmit perr node information between kmesh nodes, including node names and IPsec information, to construct an IPsec encryption system. Signed-off-by: bitcoffee <liuxin350@huawei.com>
This patch is used to load the tc program and close the tc program. Note that the attach and detach operations are not included in this patch. The attach and detach operations will be implemented in the subsequent commit operations. Signed-off-by: bitcoffee <liuxin350@huawei.com>
This PR is used to add a controller for IPsec. This controller is used to enable IPsec when the Kmesh is started, stop IPsec when the Kmesh ends, and manage IPsec configuration data. When a node in a cluster changes, the node information is sent to api-server, and information about other nodes is obtained and synchronized to the IPsec. Signed-off-by: bitcoffee <liuxin350@huawei.com>
The tc eBPF processing logic is added to the cni. When the pod is started, the corresponding tc program is mounted in the egress direction of the veth network nic of the cni tc. The tc program adds encrypted labels to the traffic on the traffic egress. After the traffic reaches the host, the traffic is encrypted by IPsec. Signed-off-by: bitcoffee <liuxin350@huawei.com>
When the management tag is added, the Kmesh adds the tc enabling logic for the existing pod. When the management tag is removed, the Kmesh adds the disabling logic. Signed-off-by: bitcoffee <liuxin350@huawei.com>
kmeshctl secret used to generate IPsec config to K8s. Signed-off-by: bitcoffee <liuxin350@huawei.com>
make gen Signed-off-by: bitcoffee <liuxin350@huawei.com>
9173430
to
99ae63e
Compare
99ae63e
to
f822150
Compare
10303e1
to
665e79b
Compare
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: hzxuzhonghu The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
What type of PR is this?
/kind feature
What this PR does / why we need it:
Which issue(s) this PR fixes:
Fixes #
Special notes for your reviewer:
Does this PR introduce a user-facing change?: