コード例 #1
0
ファイル: iptsave.go プロジェクト: romana/core
// applyRules renders desired rules and passes them as stdin to iptables-restore.
func (i *IPTsaveFirewall) applyRules(iptables *iptsave.IPtables) error {
	cmd := i.os.Cmd(iptablesRestoreBin, []string{"--noflush"})
	reader := bytes.NewReader([]byte(iptables.Render()))

	log.Tracef(trace.Inside, "In applyRules allocating stdin pipe")
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return fmt.Errorf("Failed to allocate stdin for iptables-restore - %s", err)
	}

	log.Tracef(trace.Inside, "In applyRules starting the command")
	if err := cmd.Start(); err != nil {
		return err
	}

	log.Tracef(trace.Inside, "In applyRules sending the rules")
	_, err = reader.WriteTo(stdin)
	if err != nil {
		return err
	}

	stdin.Close()

	log.Tracef(trace.Inside, "In applyRules waiting for command to complete")
	if err := cmd.Wait(); err != nil {
		log.Tracef(trace.Inside, "In applyRules failed to apply")
		return err
	}

	return nil
}
コード例 #2
0
ファイル: processor.go プロジェクト: romana/core
// process is a goroutine that consumes resource update events coming from
// Kubernetes and:
// 1. On receiving an added or deleted event:
//    i. add it to the queue
//    ii. on a timer event, send the events to handleNetworkPolicyEvents and empty the queue
// 2. On receiving a done event, exit the goroutine
func (l *KubeListener) process(in <-chan Event, done chan struct{}) {
	log.Infof("KubeListener: process(): Entered with in %v, done %v", in, done)

	timer := time.Tick(processorTickTime * time.Second)
	var networkPolicyEvents []Event

	go func() {
		for {
			select {
			case <-timer:
				if len(networkPolicyEvents) > 0 {
					log.Infof("Calling network policy handler for scheduled %d events", len(networkPolicyEvents))
					handleNetworkPolicyEvents(networkPolicyEvents, l)
					networkPolicyEvents = nil
				}
			case e := <-in:
				log.Infof("KubeListener: process(): Got %v", e)
				switch obj := e.Object.(type) {
				case *v1beta1.NetworkPolicy:
					log.Tracef(trace.Inside, "Scheduing network policy action, now scheduled %d actions", len(networkPolicyEvents))
					networkPolicyEvents = append(networkPolicyEvents, e)
				case *v1.Namespace:
					log.Tracef(trace.Inside, "Processor received namespace")
					handleNamespaceEvent(e, l)
				default:
					log.Errorf("Processor received an event of unkonwn type %s, ignoring object %s", reflect.TypeOf(obj), obj)
				}
			case <-done:
				log.Infof("KubeListener: process(): Got done")
				return
			}
		}
	}()
	return
}
コード例 #3
0
ファイル: iptsave.go プロジェクト: romana/core
// SetEndpoint implements Firewall interface. It initializes
// endpoint dependend values of firewall.
func (i *IPTsaveFirewall) SetEndpoint(netif FirewallEndpoint) error {
	log.Infof("In SetEndpoint() with endpoint <iface=%s, ip=%s, mac=%s>", netif.GetName(), netif.GetIP(), netif.GetMac())

	var err error
	i.interfaceName = netif.GetName()

	i.u32filter, i.chainPrefix, err = prepareU32Rules(netif.GetIP(), i.networkConfig)
	if err != nil {
		return err
	}

	// Assemble firewall rules needed to divert traffic
	// to/from the endpoint.
	divertFilter := makeDivertRules(netif)
	log.Tracef(trace.Inside, "In SetEndpoint() after divertFilter with\n%s", divertFilter.RenderFooter())

	// compare list of divert rules and list of current rules
	// make a list of chains filled with divert rules that need
	// to be created to match current rules.
	backendFilter := i.CurrentState.TableByName("filter")
	newChains := iptsave.MergeTables(backendFilter, divertFilter)

	// schedule divert rules that don't exist yet for installation.
	newFilter := i.DesiredState.TableByName("filter")
	newFilter.Chains = append(newFilter.Chains, newChains...)

	log.Tracef(trace.Inside, "In SetEndpoint after merge\n%s", i.CurrentState.Render())

	return err
}
コード例 #4
0
ファイル: iptables.go プロジェクト: romana/core
// ensureIPtablesChain checks if iptables chain in a desired state.
func (fw *IPtables) ensureIPtablesChain(chainName string, opType chainState) error {
	log.Infof("In ensureIPtablesChain(): %s %s", opType.String(), chainName)

	log.Tracef(trace.Inside, "In ensureIPtablesChain(): Testing chain ", chainName)
	exists := fw.isChainExistByName(chainName)
	log.Tracef(trace.Inside, "In ensureIPtablesChain(): Test for chain %s returned %b", chainName, exists)

	var iptablesAction string
	switch opType {
	case ensureChainExists:
		if exists {
			log.Tracef(trace.Inside, "In ensureIPtablesChain(): nothing to do for chain %s", chainName)
			return nil
		} else {
			iptablesAction = "-N"
		}

	case ensureChainAbsent:
		if exists {
			iptablesAction = "-D"
		} else {
			log.Tracef(trace.Inside, "In ensureIPtablesChain(): nothing to do for chain %s", chainName)
			return nil
		}
	}

	args := []string{iptablesAction, chainName}
	_, err := fw.os.Exec(iptablesCmd, args)
	return err
}
コード例 #5
0
ファイル: helpers.go プロジェクト: romana/core
// ensureInterHostRoutes ensures we have routes to every other host.
func (h Helper) ensureInterHostRoutes() error {
	log.Trace(trace.Inside, "Acquiring mutex ensureInterhostRoutes")
	h.ensureInterHostRoutesMutex.Lock()
	defer func() {
		log.Trace(trace.Inside, "Releasing mutex ensureInterhostRoutes")
		h.ensureInterHostRoutesMutex.Unlock()
	}()
	log.Trace(trace.Inside, "Acquired mutex ensureInterhostRoutes")

	via := "via"
	log.Tracef(trace.Inside, "In ensureInterHostRoutes over %v\n", h.Agent.networkConfig.otherHosts)
	for _, host := range h.Agent.networkConfig.otherHosts {
		log.Tracef(trace.Inside, "In ensureInterHostRoutes ensuring route for %v\n", host)
		_, romanaCidr, err := net.ParseCIDR(host.RomanaIp)
		if err != nil {
			return failedToParseOtherHosts(host.RomanaIp)
		}
		romanaMaskInt, _ := romanaCidr.Mask.Size()
		romanaMask := fmt.Sprintf("%d", romanaMaskInt)
		dest := host.Ip

		// wait until no one messing with routes
		// If route doesn't exist yet
		if err := h.isRouteExist(romanaCidr.IP, romanaMask); err != nil {

			// Create it
			err2 := h.createRoute(romanaCidr.IP, romanaMask, via, dest)
			if err2 != nil {
				return routeCreateError(err, romanaCidr.IP.String(), romanaMask, dest)
			}
		}
	}
	return nil
}
コード例 #6
0
ファイル: resources.go プロジェクト: romana/core
// syncNetworkPolicies compares a list of kubernetes network policies with romana network policies,
// it returns a list of kubernetes policies that don't have corresponding kubernetes network policy for them,
// and a list of romana policies that used to represent kubernetes policy but corresponding kubernetes policy is gone.
func (l *KubeListener) syncNetworkPolicies(kubePolicies []v1beta1.NetworkPolicy) (kubernetesEvents []Event, romanaPolicies []common.Policy, err error) {
	log.Infof("In syncNetworkPolicies with %v", kubePolicies)

	policies, err := getAllPoliciesFunc(l.restClient)
	if err != nil {
		return
	}

	log.Infof("In syncNetworkPolicies fetched %d romana policies", len(policies))

	// Compare kubernetes policies and all romana policies by name.
	// TODO Coparing by name is fragile should be `external_id == UID`. Stas.

	// Prepare a list of kubernetes policies that don't have corresponding
	// romana policy.
	var found bool
	accountedRomanaPolicies := make(map[int]bool)

	for kn, kubePolicy := range kubePolicies {
		namespacePolicyNamePrefix := fmt.Sprintf("kube.default.")
		found = false
		for pn, policy := range policies {
			fullPolicyName := fmt.Sprintf("%s%s", namespacePolicyNamePrefix, kubePolicy.ObjectMeta.Name)
			if fullPolicyName == policy.Name {
				found = true
				accountedRomanaPolicies[pn] = true
				break
			}
		}

		if !found {
			log.Tracef(trace.Inside, "Sync policies detected new kube policy %v", kubePolicies[kn])
			kubernetesEvents = append(kubernetesEvents, Event{KubeEventAdded, kubePolicies[kn]})
		}
	}

	// Delete romana policies that don't have corresponding
	// kubernetes policy.
	// Ignore policies that don't have "kube." prefix in the name.
	for k, _ := range policies {
		if !strings.HasPrefix(policies[k].Name, "kube.") {
			log.Tracef(trace.Inside, "Sync policies skipping policy %s since it doesn't match the prefix `kube.`", policies[k].Name)
			continue
		}

		if !accountedRomanaPolicies[k] {
			log.Infof("Sync policies detected that romana policy %d is obsolete - scheduling for deletion", policies[k].ID)
			log.Tracef(trace.Inside, "Sync policies detected that romana policy %d is obsolete - scheduling for deletion", policies[k].ID)
			romanaPolicies = append(romanaPolicies, policies[k])
		}
	}

	return
}
コード例 #7
0
ファイル: iptsave.go プロジェクト: romana/core
// ProvisionEndpoint implements Firewall interface.
func (i *IPTsaveFirewall) ProvisionEndpoint() error {
	log.Tracef(trace.Public, "In ProvisionEndpoint\n%s", i.DesiredState.Render())

	// Generate a list of rules for firewall store.
	ruleList, err := makeDbRules(i.DesiredState)
	if err != nil {
		return err
	}

	// Create rules in firewall store.
	err = i.createNewDbRules(ruleList)
	if err != nil {
		return err
	}

	// Install iptables rules from desired state.
	err = i.applyRules(i.DesiredState)
	if err != nil {
		return err
	}

	// Activate rules in firewall store.
	err = i.enableNewDbRules(ruleList)
	if err != nil {
		return err
	}

	return nil
}
コード例 #8
0
ファイル: iptsave.go プロジェクト: romana/core
// Init implements Firewall interface
func (i *IPTsaveFirewall) Init(exec utilexec.Executable, store FirewallStore, nc NetConfig) error {
	log.Infof("In Init()")

	fwstore := firewallStore{}
	fwstore.DbStore = store.GetDb()
	fwstore.mu = store.GetMutex()

	i.Store = fwstore
	i.os = exec
	i.networkConfig = nc

	// Read current iptables config.
	output, err := i.os.Exec(iptablesSaveBin, []string{})
	if err != nil {
		log.Infof("In Init(), failed to call iptables-save, %s", err)
		return err
	}

	// Parse iptables-save output.
	i.CurrentState = &iptsave.IPtables{}
	i.CurrentState.Parse(bytes.NewReader(output))

	// Inirialize desired state filter table.
	i.DesiredState = &iptsave.IPtables{}
	i.DesiredState.Tables = append(i.DesiredState.Tables, &iptsave.IPtable{Name: "filter"})
	log.Tracef(trace.Inside, "In Init(), iptables rules loaded\n, %s", i.CurrentState.Render())

	return nil
}
コード例 #9
0
ファイル: iptables.go プロジェクト: romana/core
// MergeTables merges source IPtable into destination IPtable,
// returns a list of chains with only rules from source table
// that were propagated into destination table.
func MergeTables(dstTable, srcTable *IPtable) []*IPchain {
	var returnChains []*IPchain
	var newChains []*IPchain
	var newChainFound bool

	// Walk through source and look for corresponding
	// dest chain. If dest chain exists, merge them,
	// otherwise add whole source chain to the dest table.
	for srcChainNum, srcChain := range srcTable.Chains {
		newChainFound = true
		for dstChainNum, dstChain := range dstTable.Chains {
			if dstChain.Name == srcChain.Name {
				newChainFound = false
				var newRules []*IPrule

				log.Tracef(trace.Inside, "In MergeTables, merging chain %s into table %s", srcChain.Name, dstTable.Name)

				// iptables-restore with --noflush flag works differently with
				// default builtin chains and user-defined chains.
				// When builtin chains with --noflush will not be flushed, user defined chains will, regardles
				// of the flag (at least in v1.4.21), so different merge strategies are needed.
				if dstChain.IsBuiltin() {
					newRules = MergeChains(dstTable.Chains[dstChainNum], srcTable.Chains[srcChainNum])
				} else {
					newRules = MergeUserChains(dstTable.Chains[dstChainNum], srcTable.Chains[srcChainNum])
				}

				// Make new chain similar to current source but with
				// rules returned by mergeChain, use it for return.
				returnChains = append(returnChains, &IPchain{Name: srcChain.Name, Policy: srcChain.Policy, Rules: newRules})
			}
		}

		if newChainFound {
			log.Tracef(trace.Inside, "In MergeTables, adding chain %s into table %s", srcChain.Name, dstTable.Name)
			newChains = append(newChains, srcTable.Chains[srcChainNum])
		}
	}
	dstTable.Chains = append(dstTable.Chains, newChains...)

	// Making sure that we are returning new IPchain structs
	// and not pointers to the original source chains.
	for _, c := range newChains {
		returnChains = append(returnChains, &IPchain{Name: c.Name, Policy: c.Policy, Rules: c.Rules})
	}
	return returnChains
}
コード例 #10
0
ファイル: iptsave.go プロジェクト: romana/core
// deleteIPtablesRulesBySubstring deletes rules from database and generates patch for desired state
// that would bring current state ro remove same rules that were deleted from database.
func (i *IPTsaveFirewall) deleteIPtablesRulesBySubstring(substring string) error {

	rulesPtr, err := i.Store.findIPtablesRules(substring)
	if err != nil {
		return err
	}
	log.Tracef(trace.Inside, "In Cleanup - found %d rules for interface %s", len(*rulesPtr), substring)

	// This function operates on "filter" table.
	tableDesired := i.DesiredState.TableByName("filter")
	if tableDesired == nil {
		return fmt.Errorf("In Cleanup() firewall doesn't have filter table")
	}

	tableCurrent := i.CurrentState.TableByName("filter")
	if tableCurrent == nil {
		return fmt.Errorf("In Cleanup() firewall doesn't have filter table")
	}

	// walk through rules from database, check if they are present
	// in current iptables config and schedule them for deletion if necessary.
	for _, rule := range *rulesPtr {
		log.Tracef(trace.Inside, "In Cleanup - deleting rule %s", rule.GetBody())

		// ignore inactive rules, they shouldn't be
		// in current state anyway
		if rule.State == setRuleInactive.String() {
			continue
		}

		err = i.Store.deleteIPtablesRule(&rule)
		if err != nil {
			return err
		}

		makeUndoRule(&rule, tableCurrent, tableDesired)

	}

	return nil
}
コード例 #11
0
ファイル: store.go プロジェクト: romana/core
// ensureIPtablesRule checks if given rule exists in a database and if not, creates it.
func (firewallStore *firewallStore) ensureIPtablesRule(rule *IPtablesRule) error {
	log.Info("Acquiring store mutex for listIPtablesRules")
	firewallStore.mu.Lock()
	defer func() {
		log.Info("Releasing store mutex for listIPtablesRules")
		firewallStore.mu.Unlock()
	}()
	log.Info("Acquired store mutex for listIPtablesRules")

	if firewallStore.DbStore.Db.Where("body = ?", rule.Body).First(rule).RecordNotFound() {
		log.Tracef(trace.Inside, "In ensureIPtablesRule(), rule %s not found in db - creating", rule.Body)
		err0 := firewallStore.addIPtablesRuleUnsafe(rule)
		if err0 != nil {
			log.Errorf("In ensureIPtablesRule() failed to store rule %v", rule)
			return err0
		}
	} else {
		log.Tracef(trace.Inside, "In ensureIPtablesRule(), rule %s already in db - nothing to do", rule.Body)
	}

	return nil
}
コード例 #12
0
ファイル: iptsave.go プロジェクト: romana/core
// deleteDbRules is a helper method that deletes a list of firewall rules
// from a firewall storage.
func (i IPTsaveFirewall) deleteDbRules(ruleList []*IPtablesRule) error {

	for ruleNum, _ := range ruleList {
		rule := ruleList[ruleNum]
		log.Tracef(trace.Inside, "In deleteDbRules() deleting rule %p", rule)
		err0 := i.Store.deleteIPtablesRule(rule)
		if err0 != nil {
			log.Errorf("In deleteDbRules() failed to enable rule %v", rule)
			return err0
		}
	}

	return nil
}
コード例 #13
0
ファイル: iptsave.go プロジェクト: romana/core
// enableNewDbRules is a halper method that sets `enabled` flag for
// a list of firewall rules in a firewall storage.
func (i IPTsaveFirewall) enableNewDbRules(ruleList []*IPtablesRule) error {

	for ruleNum, _ := range ruleList {
		rule := ruleList[ruleNum]
		log.Tracef(trace.Inside, "In switchIPtablesRule() activating rule %p", rule)
		err0 := i.Store.switchIPtablesRule(rule, setRuleActive)
		if err0 != nil {
			log.Errorf("In enableNewDbRules() failed to enable rule %v", rule)
			return err0
		}
	}

	return nil
}
コード例 #14
0
ファイル: iptsave.go プロジェクト: romana/core
// createNewDbRules is a helper method that puts a list of firewall rules
// in a firewall storage.
func (i IPTsaveFirewall) createNewDbRules(ruleList []*IPtablesRule) error {

	for ruleNum, _ := range ruleList {
		rule := ruleList[ruleNum]
		log.Tracef(trace.Inside, "In createNewDbRules() storing rule %p", rule)
		err0 := i.Store.ensureIPtablesRule(rule)
		if err0 != nil {
			log.Errorf("In createNewDbRules() failed to store rule %v", rule)
			return err0
		}
	}

	return nil
}
コード例 #15
0
ファイル: resources.go プロジェクト: romana/core
// handleNetworkPolicyEvents by creating or deleting romana policies.
func handleNetworkPolicyEvents(events []Event, l *KubeListener) {
	// TODO optimise deletion, search policy by name/id
	// and delete by id rather then sending full policy body.
	// Stas.
	var deleteEvents []v1beta1.NetworkPolicy
	var createEvents []v1beta1.NetworkPolicy

	for _, event := range events {
		switch event.Type {
		case KubeEventAdded:
			createEvents = append(createEvents, *event.Object.(*v1beta1.NetworkPolicy))
		case KubeEventDeleted:
			deleteEvents = append(deleteEvents, *event.Object.(*v1beta1.NetworkPolicy))
		default:
			log.Tracef(trace.Inside, "Ignoring %s event in handleNetworkPolicyEvents", event.Type)
		}
	}

	// Translate new network policies into romana policies.
	createPolicyList, kubePolicy, err := PTranslator.Kube2RomanaBulk(createEvents)
	if err != nil {
		log.Errorf("Not all kubernetes policies could be translated to Romana policies. Attempted %d, success %d, fail %d, error %s", len(createEvents), len(createPolicyList), len(kubePolicy), err)
	}
	for kn, _ := range kubePolicy {
		log.Errorf("Failed to translate kubernetes policy %v", kubePolicy[kn])
	}

	// Create new policies.
	for pn, _ := range createPolicyList {
		err = l.addNetworkPolicy(createPolicyList[pn])
		if err != nil {
			log.Errorf("Error adding policy with Kubernetes ID %s: %s", createPolicyList[pn].ExternalID, err)
		}
	}

	// Delete old policies.
	for _, policy := range deleteEvents {
		// policy name is derived as below in translator and thus use the
		// same technique to derive the policy name here for deleting it.
		policyName := fmt.Sprintf("kube.%s.%s", policy.ObjectMeta.Namespace, policy.ObjectMeta.Name)
		// TODO this must be changed to use External ID
		err = l.deleteNetworkPolicy(common.Policy{Name: policyName})
		if err != nil {
			log.Errorf("Error deleting policy %s (%s): %s", policyName, policy.GetUID(), err)
		}
	}
}
コード例 #16
0
ファイル: helpers.go プロジェクト: romana/core
// waitForIface waits for network interface to become available in the system.
func (h Helper) waitForIface(expectedIface string) bool {
	for i := 0; i <= h.Agent.waitForIfaceTry; i++ {
		log.Tracef(trace.Inside, "Helper: Waiting for interface %s, %d attempt", expectedIface, i)
		ifaceList, err := net.Interfaces()
		log.Trace(trace.Inside, "Agent: Entering podUpHandlerAsync()")
		if err != nil {
			log.Warn("Warning: Helper: failed to read net.Interfaces()")
		}
		for iface := range ifaceList {
			if ifaceList[iface].Name == expectedIface {
				return true
			}
		}
		time.Sleep(10 * time.Second)
	}
	return false
}
コード例 #17
0
ファイル: iptables.go プロジェクト: romana/core
// MergeUserChains merges rules from the source chain into the destination chain
// produces list of rules that combines rules from both chains with order
// preserved as much as possible.
func MergeUserChains(dstChain, srcChain *IPchain) []*IPrule {
	var retRules []*IPrule
	dstLen := len(dstChain.Rules)
	srcLen := len(srcChain.Rules)

	// if one chain is empty then other chain is a result of the merge
	if srcLen == 0 {
		return dstChain.Rules
	}
	if dstLen == 0 {
		return srcChain.Rules
	}

	maxLen := 0
	if dstLen <= srcLen {
		maxLen = srcLen
	} else {
		maxLen = dstLen
	}

	// Merge strategy is to walk both rule lists at same time and compare the rules at same position
	// if rules match then one of them added to the result, otherwise both are.
	for i := 0; i < maxLen; i++ {
		if i <= dstLen && i <= srcLen {
			log.Tracef(trace.Inside, "In MergeUserTables, counter=%d, src table len=%d, dst table len=%d", i, srcLen, dstLen)
			if dstChain.Rules[i].String() == srcChain.Rules[i].String() {
				retRules = append(retRules, dstChain.Rules[i])
			} else {
				retRules = append(retRules, dstChain.Rules[i])
				retRules = append(retRules, srcChain.Rules[i])

			}
		} else if i <= dstLen {
			retRules = append(retRules, dstChain.Rules[i])
		} else if i <= srcLen {
			retRules = append(retRules, srcChain.Rules[i])
		} else {
			// Should never get here.
			panic(fmt.Sprintf("Unexpected state in MergeUserChains, counter=%d, source len=%d, dst len=%d", i, srcLen, dstLen))
		}
	}

	return retRules
}
コード例 #18
0
ファイル: handlers.go プロジェクト: romana/core
// vmDownHandler handles HTTP requests for endpoints teardown.
func (a *Agent) vmDownHandler(input interface{}, ctx common.RestContext) (interface{}, error) {
	log.Tracef(trace.Private, "In vmDownHandler() with %T %v", input, input)
	netif := input.(*NetIf)
	if netif.Name == "" {
		// This is a request from OpenStack Mech driver who does not have a name,
		// let's find it by mac.
		err := a.store.findNetIf(netif)
		if err != nil {
			return nil, err
		}
	}
	log.Infof("Agent: Provisioning DHCP for %s, IP %s Mac %s\n", netif.Name, netif.IP, netif.Mac)

	if err := a.leaseFile.provisionLease(netif, leaseRemove); err != nil {
		log.Error(agentError(err))
		return "Error removing DHCP lease", agentError(err)
	}

	// We need new firewall instance here to use it's Cleanup()
	// to uninstall firewall rules related to the endpoint.
	fw, err := firewall.NewFirewall(a.getFirewallType())
	if err != nil {
		return nil, err
	}

	err = fw.Init(a.Helper.Executor, a.store, a.networkConfig)
	if err != nil {
		return nil, err
	}

	err = fw.Cleanup(netif)
	if err != nil {
		return nil, err
	}
	err = a.store.deleteNetIf(netif)
	if err != nil {
		return nil, err
	}
	return "OK", nil
}
コード例 #19
0
ファイル: translate.go プロジェクト: romana/core
// translateTarget analizes kubePolicy and fills romanaPolicy.AppliedTo field.
func (tg *TranslateGroup) translateTarget(translator *Translator) error {

	// Translate kubernetes namespace into romana tenant. Must be defined.
	tenantCacheEntry := translator.checkTenantInCache(tg.kubePolicy.ObjectMeta.Namespace)
	if tenantCacheEntry == nil {
		log.Errorf("Tenant not found when translating policy %v", tg.romanaPolicy)
		return TranslatorError{ErrorTenantNotInCache, nil}
	}

	// Empty PodSelector means policy applied to the entire namespace.
	if len(tg.kubePolicy.Spec.PodSelector.MatchLabels) == 0 {
		tg.romanaPolicy.AppliedTo = []common.Endpoint{
			common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID},
		}

		log.Tracef(trace.Inside, "Segment was not specified in policy %v, assuming target is a namespace", tg.kubePolicy)
		return nil
	}

	// If PodSelector is not empty then segment label must be defined.
	kubeSegmentID, ok := tg.kubePolicy.Spec.PodSelector.MatchLabels[translator.segmentLabelName]
	if !ok || kubeSegmentID == "" {
		log.Errorf("Expected segment to be specified in podSelector part as %s", translator.segmentLabelName)
		return common.NewError("Expected segment to be specified in podSelector part as '%s'", translator.segmentLabelName)
	}

	// Translate kubernetes segment label into romana segment.
	segment, err := translator.getOrAddSegment(tg.kubePolicy.ObjectMeta.Namespace, kubeSegmentID)
	if err != nil {
		log.Errorf("Error in translate while calling l.getOrAddSegment with %s and %s - error %s", tg.kubePolicy.ObjectMeta.Namespace, kubeSegmentID, err)
		return err
	}

	tg.romanaPolicy.AppliedTo = []common.Endpoint{
		common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID, SegmentID: segment.ID},
	}

	return nil
}
コード例 #20
0
ファイル: iptsave.go プロジェクト: romana/core
// Cleanup implements Firewall interface.
func (i *IPTsaveFirewall) Cleanup(netif FirewallEndpoint) error {

	// Delete netif related rules from ifirewall store and schedule
	// them for deletion from current state.
	// TODO it is possible that someone will make a chain
	// with a name that matchies interface name and this call
	// will delete all rules from such a chain.
	// This is very unlikely but still should be
	// addressed just in case. Stas.
	err := i.deleteIPtablesRulesBySubstring(netif.GetName())
	if err != nil {
		return err
	}

	// Delete netif related rules from current state.
	err = i.applyRules(i.DesiredState)
	if err != nil {
		return err
	}

	log.Tracef(trace.Inside, "In Cleanup \n%s", i.DesiredState.Render())
	return nil
}
コード例 #21
0
ファイル: resources.go プロジェクト: romana/core
// handleAnnotations on a namespace by implementing extra features requested through the annotation
func handleAnnotations(o *v1.Namespace, l *KubeListener) {
	log.Tracef(trace.Private, "In handleAnnotations")

	// We only care about one annotation for now.
	HandleDefaultPolicy(o, l)
}
コード例 #22
0
ファイル: translate.go プロジェクト: romana/core
/// makeNextIngressPeer analyzes current Ingress rule and adds new Peer to romanaPolicy.Peers.
func (tg *TranslateGroup) makeNextIngressPeer(translator *Translator) error {
	ingress := tg.kubePolicy.Spec.Ingress[tg.ingressIndex]

	for _, fromEntry := range ingress.From {
		tenantCacheEntry := &TenantCacheEntry{}

		// Exactly one of From.PodSelector or From.NamespaceSelector must be specified.
		if fromEntry.PodSelector == nil && fromEntry.NamespaceSelector == nil {
			log.Errorf("Either PodSElector or NamespacesSelector must be specified")
			return common.NewError("Either PodSElector or NamespacesSelector must be specified")
		} else if fromEntry.PodSelector != nil && fromEntry.NamespaceSelector != nil {
			log.Errorf("Exactly one of PodSElector or NamespacesSelector must be specified")
			return common.NewError("Exactly on of PodSElector or NamespacesSelector must be specified")
		}

		// This ingress field matching a namespace which will be our source tenant.
		if fromEntry.NamespaceSelector != nil {
			tenantName, ok := fromEntry.NamespaceSelector.MatchLabels[translator.tenantLabelName]
			if !ok || tenantName == "" {
				log.Errorf("Expected tenant name to be specified in NamespaceSelector field with a key %s", translator.tenantLabelName)
				return common.NewError("Expected tenant name to be specified in NamespaceSelector field with a key %s", translator.tenantLabelName)
			}

			tenantCacheEntry = translator.checkTenantInCache(tenantName)
			if tenantCacheEntry == nil {
				log.Errorf("Tenant not not found when translating policy %v", tg.romanaPolicy)
				return TranslatorError{ErrorTenantNotInCache, nil}
			}

			// Found a source tenant, let's register it as romana Peeer.
			tg.romanaPolicy.Ingress[tg.ingressIndex].Peers = append(tg.romanaPolicy.Ingress[tg.ingressIndex].Peers,
				common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID})
		}

		// This ingress field matches a segment and source tenant is a same as target tenant.
		if fromEntry.PodSelector != nil {

			// Check if source/target tenant in cache.
			tenantCacheEntry = translator.checkTenantInCache(tg.kubePolicy.ObjectMeta.Namespace)
			if tenantCacheEntry == nil {
				log.Errorf("Tenant not not found when translating policy %v", tg.romanaPolicy)
				return TranslatorError{ErrorTenantNotInCache, nil}
			}

			// If podSelector is empty match all traffic from the tenant.
			if len(fromEntry.PodSelector.MatchLabels) == 0 {
				tg.romanaPolicy.Ingress[tg.ingressIndex].Peers = append(tg.romanaPolicy.Ingress[tg.ingressIndex].Peers,
					common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID})

				log.Tracef(trace.Inside, "No segment specified when translating ingress rule %v", tg.kubePolicy.Spec.Ingress[tg.ingressIndex])
				return nil
			}

			// Get segment name from podSelector.
			kubeSegmentID, ok := fromEntry.PodSelector.MatchLabels[translator.segmentLabelName]
			if !ok || kubeSegmentID == "" {
				log.Errorf("Expected segment to be specified in podSelector part as %s", translator.segmentLabelName)
				return common.NewError("Expected segment to be specified in podSelector part as '%s'", translator.segmentLabelName)
			}

			// Translate kubernetes segment name into romana segment.
			segment, err := translator.getOrAddSegment(tenantCacheEntry.Tenant.Name, kubeSegmentID)
			if err != nil {
				log.Errorf("Error in translate while calling l.getOrAddSegment with %s and %s - error %s", tenantCacheEntry.Tenant.Name, kubeSegmentID, err)
				return err
			}

			// Register source tenant/segment as a romana Peer.
			tg.romanaPolicy.Ingress[tg.ingressIndex].Peers = append(tg.romanaPolicy.Ingress[tg.ingressIndex].Peers,
				common.Endpoint{TenantID: tenantCacheEntry.Tenant.ID, TenantExternalID: tenantCacheEntry.Tenant.ExternalID, SegmentID: segment.ID})
		}

	}
	return nil
}
コード例 #23
0
ファイル: iptables.go プロジェクト: romana/core
// parseItem installs given item in its appropriate place in IPtables.Tables tree.
func (i *IPtables) parseItem(item Item) {
	switch item.Type {
	case itemComment:
		// Ignore comment items.
		return
	case itemTable:
		// If item is a table, initialize a new Itable.
		i.Tables = append(i.Tables, &IPtable{Name: item.Body})
	case itemChain:
		// If item is a chain, add a new chain to the last table.
		table := i.lastTable()
		if table == nil {
			panic("Chain before table")
		} // TODO crash here

		log.Tracef(trace.Inside, "In ParseItem adding chain %s to the table %s", item.Body, table.Name)

		table.Chains = append(table.Chains, &IPchain{Name: item.Body})
	case itemChainPolicy:
		// If item is a chain policy, set a policy for the last chain.
		table := i.lastTable()

		log.Tracef(trace.Inside, "In ParseItem table %s has %d chains", table.Name, len(table.Chains))

		chain := table.lastChain()
		if table == nil || chain == nil {
			panic("Chain policy before table/chain")
		} // TODO crash here

		chain.Policy = item.Body
	case itemChainCounter:
		// If item is a chain counter, set a chain counter for the last chain.
		table := i.lastTable()
		chain := table.lastChain()
		if table == nil || chain == nil {
			panic("Chain policy before table/chain")
		} // TODO crash here

		chain.Counters = item.Body
	case itemCommit:
		// Ignore COMMIT items.
		return // TODO, ignored for now, should probably be in the model
	case itemRule:
		// If item is a rule, add a new rule in to the proper chain,
		// and initialize i.currentRule.
		table := i.lastTable()
		chain := table.ChainByName(item.Body)
		if table == nil || chain == nil {
			panic("Rule before table/chain")
		} // TODO crash here

		newRule := new(IPrule)
		chain.Rules = append(chain.Rules, newRule)

		i.currentRule = newRule
	case itemRuleMatch:
		// If item is a rule match, add new match to the current rule.
		if i.currentRule == nil {
			panic("RuleMatch before table/chain/rule")
		} // TODO crash here

		i.currentRule.Match = append(i.currentRule.Match, &Match{Body: item.Body})
	case itemAction:
		// If item is a rule action, add a new target to the current rule.
		if i.currentRule == nil {
			panic("RuleMatch before table/chain/rule")
		} // TODO crash here
		i.currentRule.Action = IPtablesAction{Body: item.Body}

	}

	return
}
コード例 #24
0
ファイル: iptsave.go プロジェクト: romana/core
// makeDivertRules creates iptables "filter" table with rules to divert traffic
// to/from given endpoint into romana chains.
func makeDivertRules(netif FirewallEndpoint) *iptsave.IPtable {
	log.Tracef(trace.Private, "In makeDivertRules() with %s", netif.GetName())
	divertTable := iptsave.IPtable{
		Name: "filter",
		Chains: []*iptsave.IPchain{
			&iptsave.IPchain{
				Name:   "INPUT",
				Policy: "-",
				Rules: []*iptsave.IPrule{
					&iptsave.IPrule{
						Action: iptsave.IPtablesAction{
							Body: ChainNameEndpointToHost,
						},
						Match: []*iptsave.Match{
							&iptsave.Match{
								Negated: false,
								Body:    "-i " + netif.GetName(),
							},
						},
					},
				},
			},
			&iptsave.IPchain{
				Name:   "OUTPUT",
				Policy: "-",
				Rules: []*iptsave.IPrule{
					&iptsave.IPrule{
						Action: iptsave.IPtablesAction{
							Body: ChainNameHostToEndpoint,
						},
						Match: []*iptsave.Match{
							&iptsave.Match{
								Negated: false,
								Body:    "-o " + netif.GetName(),
							},
						},
					},
				},
			},
			&iptsave.IPchain{
				Name:   "FORWARD",
				Policy: "-",
				Rules: []*iptsave.IPrule{
					&iptsave.IPrule{
						Action: iptsave.IPtablesAction{
							Body: ChainNameEndpointEgress,
						},
						Match: []*iptsave.Match{
							&iptsave.Match{
								Negated: false,
								Body:    "-i " + netif.GetName(),
							},
						},
					},
					&iptsave.IPrule{
						Action: iptsave.IPtablesAction{
							Body: ChainNameEndpointIngress,
						},
						Match: []*iptsave.Match{
							&iptsave.Match{
								Negated: false,
								Body:    "-o " + netif.GetName(),
							},
						},
					},
				},
			},
			&iptsave.IPchain{
				Name:   ChainNameEndpointToHost,
				Policy: "-",
			},
			/* Skipping this chain because it is similar to ChainNameEndpointIngress
			&iptsave.IPchain{
				Name: ChainNameHostToEndpoint,
				Policy: "-",
			},
			*/
			&iptsave.IPchain{
				Name:   ChainNameEndpointEgress,
				Policy: "-",
			},
			&iptsave.IPchain{
				Name:   ChainNameEndpointIngress,
				Policy: "-",
			},
		},
	}

	return &divertTable

}
コード例 #25
0
ファイル: config.go プロジェクト: romana/core
// identifyCurrentHost discovers network configuration
// of the host we are running on.
// We need to know public IP and Romana gateway IP of the current host.
// This is done by matching current host IP addresses against what topology
// service thinks the host address is.
// If no match is found we assume we are running on host which is not
// part of the Romana setup and spit error out.
func (a Agent) identifyCurrentHost() error {
	client, err := common.NewRestClient(common.GetRestClientConfig(a.config))

	if err != nil {
		return agentError(err)
	}
	topologyURL, err := client.GetServiceUrl("topology")
	if err != nil {
		return agentError(err)
	}
	index := common.IndexResponse{}
	err = client.Get(topologyURL, &index)
	if err != nil {
		return agentError(err)
	}
	dcURL := index.Links.FindByRel("datacenter")
	a.networkConfig.dc = common.Datacenter{}
	err = client.Get(dcURL, &a.networkConfig.dc)
	if err != nil {
		return agentError(err)
	}

	hostURL := index.Links.FindByRel("host-list")
	hosts := []common.Host{}
	err = client.Get(hostURL, &hosts)
	if err != nil {
		return agentError(err)
	}
	log.Trace(trace.Inside, "Retrieved hosts list, found", len(hosts), "hosts")

	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return err
	}

	log.Tracef(trace.Inside, "Searching %d interfaces for a matching host configuration: %v", len(addrs), addrs)

	// Find an interface that matches a Romana CIDR
	// and store that interface's IP address.
	// It will be used when configuring iptables and routes to tap interfaces.
	for i, host := range hosts {
		_, romanaCIDR, err := net.ParseCIDR(host.RomanaIp)
		if err != nil {
			log.Tracef(trace.Inside, "Unable to parse '%s' (%s). Skipping.", host.RomanaIp, err)
			continue
		}
		for _, addr := range addrs {
			ipnet, ok := addr.(*net.IPNet)
			if !ok {
				continue
			}
			if romanaCIDR.Contains(ipnet.IP) {
				// Check that it's the same subnet size
				s1, _ := romanaCIDR.Mask.Size()
				s2, _ := ipnet.Mask.Size()
				if s1 != s2 {
					continue
				}
				// OK, we're happy with this result
				a.networkConfig.romanaGW = ipnet.IP
				a.networkConfig.romanaGWMask = ipnet.Mask
				// Retain the other hosts that were listed.
				// This will be used for creating inter-host routes.
				a.networkConfig.otherHosts = append(a.networkConfig.otherHosts, hosts[0:i]...)
				a.networkConfig.otherHosts = append(a.networkConfig.otherHosts, hosts[i+1:]...)
				log.Trace(trace.Inside, "Found match for CIDR", romanaCIDR, "using address", ipnet.IP)
				return nil
			}
		}
	}
	return agentErrorString("Unable to find interface matching any Romana CIDR")
}
コード例 #26
0
ファイル: handlers.go プロジェクト: romana/core
func prepareFirewallRules(fw firewall.Firewall, nc *NetworkConfig, rules RuleSet, firewallProvider firewall.Provider) error {
	metadata := fw.Metadata()

	var defaultRules []firewall.FirewallRule
	var u32filter string = metadata["u32filter"].(string)
	var hostAddr = nc.RomanaGW()
	var formatBody string

	switch firewallProvider {
	case firewall.ShellexProvider:
		var chainNames []string = metadata["chains"].([]string)

		for _, rule := range rules {
			log.Tracef(trace.Inside, "In prepareFirewallRules(), with %v", rule)

			var currentChain string
			switch rule.Direction {
			case EgressLocalDirection:
				currentChain = chainNames[firewall.InputChainIndex]
			case EgressGlobalDirection:
				currentChain = chainNames[firewall.ForwardOutChainIndex]
			case IngressGlobalDirection:
				currentChain = chainNames[firewall.ForwardInChainIndex]
			default:
				return fmt.Errorf("Error, unsupported rule direction type with firewall provider %d", firewallProvider)
			}

			switch rule.Format {
			case FormatChain:
				formatBody = fmt.Sprintf(rule.Body, currentChain)
			case FormatChainHostU32TenantSegment:
				formatBody = fmt.Sprintf(rule.Body, currentChain, hostAddr, u32filter)
			default:
				return fmt.Errorf("Error, unsupported rule format type with firewall provider %d", firewallProvider)
			}

			r := firewall.NewFirewallRule()
			r.SetBody(formatBody)

			switch rule.Position {
			case DefaultPosition:
				defaultRules = append(defaultRules, r)
			default:
				return fmt.Errorf("Error, unsupported rule position with firewall provider %d", firewallProvider)
			}
		}
	case firewall.IPTsaveProvider:
		for _, rule := range rules {
			log.Tracef(trace.Inside, "In prepareFirewallRules(), with %v", rule)

			var currentChain string
			switch rule.Direction {
			case EgressLocalDirection:
				currentChain = firewall.ChainNameEndpointToHost
			case EgressGlobalDirection:
				currentChain = firewall.ChainNameEndpointEgress
			case IngressGlobalDirection:
				currentChain = firewall.ChainNameEndpointIngress
			default:
				return fmt.Errorf("Error, unsupported rule direction type with firewall provider %d", firewallProvider)
			}

			switch rule.Format {
			case FormatChain:
				formatBody = fmt.Sprintf(rule.Body, currentChain)
			case FormatChainHostU32TenantSegment:
				formatBody = fmt.Sprintf(rule.Body, currentChain, hostAddr, u32filter)
			default:
				return fmt.Errorf("Error, unsupported rule format type with firewall provider %d", firewallProvider)
			}

			r := firewall.NewFirewallRule()
			r.SetBody(formatBody)

			switch rule.Position {
			case TopPosition:
				fw.EnsureRule(r, firewall.EnsureFirst)
			case BottomPosition:
				fw.EnsureRule(r, firewall.EnsureLast)
			default:
				return fmt.Errorf("Error, unsupported rule position with firewall provider %d", firewallProvider)
			}
		}
	default:
		return fmt.Errorf("Error, unsupported firewall provider type when preparing firewall rules")
	}

	return nil
}